home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / normal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-05  |  104.2 KB  |  4,556 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * Contains the main routine for processing characters in command mode.
  11.  * Communicates closely with the code in ops.c to handle the operators.
  12.  */
  13.  
  14. #include "vim.h"
  15.  
  16. /*
  17.  * The Visual area is remembered for reselection.
  18.  */
  19. static int    resel_VIsual_mode = NUL;    /* 'v', 'V', or Ctrl-V */
  20. static linenr_t    resel_VIsual_line_count;    /* number of lines */
  21. static colnr_t    resel_VIsual_col;        /* nr of cols or end col */
  22.  
  23. /*
  24.  * Operator characters; The order must correspond to the defines in vim.h!
  25.  */
  26. static char_u *op_chars = (char_u *)"dyc<>!~=Q:UuJq";
  27.  
  28. static void    op_colon __ARGS((OPARG *oap, int VIsual_was_active));
  29. #ifdef USE_MOUSE
  30. static void    find_start_of_word __ARGS((FPOS *));
  31. static void    find_end_of_word __ARGS((FPOS *));
  32. static int    get_mouse_class __ARGS((int));
  33. #endif
  34. static void    prep_redo_cmd __ARGS((CMDARG *cap));
  35. static void    prep_redo __ARGS((int regname, long, int, int, int, int));
  36. static int    checkclearop __ARGS((OPARG *oap));
  37. static int    checkclearopq __ARGS((OPARG *oap));
  38. static void    clearop __ARGS((OPARG *oap));
  39. static void    clearopbeep __ARGS((OPARG *oap));
  40. #ifdef SHOWCMD
  41. static void    del_from_showcmd __ARGS((int));
  42. #endif
  43.  
  44. static void    do_gd __ARGS((OPARG *oap, int nchar));
  45. static int    screengo __ARGS((OPARG *oap, int dir, long dist));
  46. static void    do_scroll_line __ARGS((CMDARG *cap, int is_ctrl_e));
  47. static void    do_zet __ARGS((CMDARG *cap));
  48. static void    do_colon __ARGS((CMDARG *cap));
  49. static void    do_ident __ARGS((CMDARG *cap, char_u **searchp));
  50. static void    do_scroll __ARGS((CMDARG *cap));
  51. static void    do_right __ARGS((CMDARG *cap));
  52. static int    do_left __ARGS((CMDARG *cap));
  53. #ifdef FILE_IN_PATH
  54. static void    do_gotofile __ARGS((CMDARG *cap));
  55. #endif
  56. static void    do_normal_search __ARGS((CMDARG *cap, char_u **searchp, int dont_set_mark));
  57. static void    do_csearch __ARGS((CMDARG *cap, int dir, int type));
  58. static void    do_brackets __ARGS((CMDARG *cap, int dir));
  59. static void    do_percent __ARGS((CMDARG *cap));
  60. static int    do_replace __ARGS((CMDARG *cap));
  61. static void    switch_visual __ARGS((CMDARG *cap));
  62. static void    do_swapchar __ARGS((CMDARG *cap));
  63. static void    do_cursormark __ARGS((CMDARG *cap, int flag, FPOS *pos));
  64. static void    do_visop __ARGS((CMDARG *cap));
  65. static void    do_optrans __ARGS((CMDARG *cap));
  66. static void    do_gomark __ARGS((CMDARG *cap, int flag));
  67. static void    do_pcmark __ARGS((CMDARG *cap));
  68. static void    do_regname __ARGS((CMDARG *cap, linenr_t *opnump));
  69. static void    do_visual __ARGS((CMDARG *cap));
  70. static int    do_g_cmd __ARGS((CMDARG *cap, char_u **searchp));
  71. static int    do_opencmd __ARGS((CMDARG *cap));
  72. static void    do_operator __ARGS((CMDARG *cap));
  73. static void    do_lineop __ARGS((CMDARG *cap));
  74. static void    do_bck_word __ARGS((CMDARG *cap, int type));
  75. static void    do_wordcmd __ARGS((CMDARG *cap, int type));
  76. static void    do_goto __ARGS((OPARG *oap, long lnum));
  77. static void    do_esc __ARGS((CMDARG *oap, linenr_t opnum));
  78. #ifdef TEXT_OBJECTS
  79. static void    do_object __ARGS((CMDARG *cap));
  80. #endif
  81. static void    do_at __ARGS((CMDARG *cap));
  82. static void    do_halfpage __ARGS((CMDARG *cap));
  83. static void    do_pput __ARGS((CMDARG *cap));
  84.  
  85. /*
  86.  * normal
  87.  *
  88.  * Execute a command in normal mode.
  89.  *
  90.  * This is basically a big switch with the cases arranged in rough categories
  91.  * in the following order:
  92.  *
  93.  *    0. Macros (q, @)
  94.  *    1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  95.  *    2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  96.  *    3. Cursor motions (G, H, M, L, l, K_RIGHT,  , h, K_LEFT, ^H, k, K_UP,
  97.  *     ^P, +, CR, LF, j, K_DOWN, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
  98.  *    4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  99.  *    5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  100.  *    6. Inserts (A, a, I, i, o, O, R)
  101.  *    7. Operators (~, d, c, y, >, <, !, =, Q)
  102.  *    8. Abbreviations (x, X, D, C, s, S, Y, &)
  103.  *    9. Marks (m, ', `, ^O, ^I)
  104.  *   10. Register name setting ('"')
  105.  *   11. Visual (v, V, ^V)
  106.  *   12. Suspend (^Z)
  107.  *   13. Window commands (^W)
  108.  *   14. extended commands (starting with 'g')
  109.  *   15. mouse click
  110.  *   16. scrollbar movement
  111.  *   17. The end (ESC)
  112.  */
  113.  
  114.     void
  115. normal_cmd(oap, toplevel)
  116.     OPARG    *oap;
  117.     int        toplevel;    /* TRUE when called from main() */
  118. {
  119.     static linenr_t opnum = 0;            /* count before an operator */
  120.     CMDARG        ca;                /* command arguments */
  121.     int            c;
  122.     int            flag = FALSE;
  123.     int            type = 0;            /* type of operation */
  124.     int            dir = FORWARD;        /* search direction */
  125.     char_u        *searchbuff = NULL;        /* buffer for search string */
  126.     int            command_busy = FALSE;
  127.     int            ctrl_w = FALSE;        /* got CTRL-W command */
  128.     int            old_col = curwin->w_curswant;
  129.     int            dont_adjust_op_end = FALSE;
  130.     FPOS        old_pos;            /* cursor position before command */
  131. #ifdef SHOWCMD
  132.     int            need_flushbuf;        /* need to call out_flush() */
  133. #endif
  134.  
  135.     vim_memset(&ca, 0, sizeof(ca));
  136.     ca.oap = oap;
  137.  
  138. #ifdef USE_SNIFF
  139.     want_sniff_request = sniff_connected;
  140. #endif
  141.  
  142.     /*
  143.      * If there is an operator pending, then the command we take this time
  144.      * will terminate it. Finish_op tells us to finish the operation before
  145.      * returning this time (unless the operation was cancelled).
  146.      */
  147. #ifdef USE_GUI
  148.     c = finish_op;
  149. #endif
  150.     finish_op = (oap->op_type != OP_NOP);
  151. #ifdef USE_GUI
  152.     if (finish_op != c && gui.in_use)
  153.     gui_upd_cursor_shape();    /* change shape of cursor */
  154. #endif
  155.  
  156.     if (!finish_op && !oap->regname)
  157.     opnum = 0;
  158.  
  159.     State = NORMAL_BUSY;
  160. #ifdef USE_GUI_WIN32
  161.     dont_scroll = FALSE;    /* allow scrolling here */
  162. #endif
  163.     c = vgetc();
  164. #ifdef HAVE_LANGMAP
  165.     LANGMAP_ADJUST(c, TRUE);
  166. #endif
  167.     if (c == NUL)
  168.     c = K_ZERO;
  169. #ifdef SHOWCMD
  170.     need_flushbuf = add_to_showcmd(c);
  171. #endif
  172.  
  173. getcount:
  174.     /* Pick up any leading digits and compute ca.count0 */
  175.     while (    (c >= '1' && c <= '9')
  176.         || (ca.count0 != 0 && (c == K_DEL || c == '0')))
  177.     {
  178.     if (c == K_DEL)
  179.     {
  180.         ca.count0 /= 10;
  181. #ifdef SHOWCMD
  182.         del_from_showcmd(4);    /* delete the digit and ~@% */
  183. #endif
  184.     }
  185.     else
  186.         ca.count0 = ca.count0 * 10 + (c - '0');
  187.     if (ca.count0 < 0)        /* got too large! */
  188.         ca.count0 = 999999999;
  189.     if (ctrl_w)
  190.     {
  191.         ++no_mapping;
  192.         ++allow_keys;        /* no mapping for nchar, but keys */
  193.     }
  194.     c = vgetc();
  195. #ifdef HAVE_LANGMAP
  196.     LANGMAP_ADJUST(c, TRUE);
  197. #endif
  198.     if (ctrl_w)
  199.     {
  200.         --no_mapping;
  201.         --allow_keys;
  202.     }
  203. #ifdef SHOWCMD
  204.     need_flushbuf |= add_to_showcmd(c);
  205. #endif
  206.     }
  207.  
  208. /*
  209.  * If we got CTRL-W there may be a/another count
  210.  */
  211.     if (c == Ctrl('W') && !ctrl_w && oap->op_type == OP_NOP)
  212.     {
  213.     ctrl_w = TRUE;
  214.     opnum = ca.count0;            /* remember first count */
  215.     ca.count0 = 0;
  216.     ++no_mapping;
  217.     ++allow_keys;                /* no mapping for nchar, but keys */
  218.     c = vgetc();                /* get next character */
  219. #ifdef HAVE_LANGMAP
  220.     LANGMAP_ADJUST(c, TRUE);
  221. #endif
  222.     --no_mapping;
  223.     --allow_keys;
  224. #ifdef SHOWCMD
  225.     need_flushbuf |= add_to_showcmd(c);
  226. #endif
  227.     goto getcount;                /* jump back */
  228.     }
  229.  
  230.     ca.cmdchar = c;
  231.  
  232.     /*
  233.      * If we're in the middle of an operator (including after entering a yank
  234.      * buffer with '"') AND we had a count before the
  235.      * operator, then that count overrides the current value of ca.count0.
  236.      * What * this means effectively, is that commands like "3dw" get turned
  237.      * into "d3w" which makes things fall into place pretty neatly.
  238.      * If you give a count before AND after the operator, they are multiplied.
  239.      */
  240.     if (opnum != 0)
  241.     {
  242.         if (ca.count0)
  243.         ca.count0 *= opnum;
  244.         else
  245.         ca.count0 = opnum;
  246.     }
  247.  
  248.     /*
  249.      * Always remember the count.  It will be set to zero (on the next call,
  250.      * above) when there is no pending operator.
  251.      * When called from main(), save the count for use by the "count" built-in
  252.      * variable.
  253.      */
  254.     opnum = ca.count0;
  255.     if (toplevel)
  256.     global_opnum = opnum;
  257.  
  258.     ca.count1 = (ca.count0 == 0 ? 1 : ca.count0);
  259.  
  260.     /*
  261.      * Get an additional character if we need one.
  262.      * For CTRL-W we already got it when looking for a count.
  263.      */
  264.     if (ctrl_w)
  265.     {
  266.     ca.nchar = ca.cmdchar;
  267.     ca.cmdchar = Ctrl('W');
  268.     }
  269.     else if (    (oap->op_type == OP_NOP
  270.         && vim_strchr((char_u *)"@zm\"", ca.cmdchar) != NULL)
  271.         || (oap->op_type == OP_NOP
  272.         && !VIsual_active
  273.         && (ca.cmdchar == 'r' || ca.cmdchar == 'Z'))
  274.         || vim_strchr((char_u *)"tTfF[]g'`", ca.cmdchar) != NULL
  275.         || (ca.cmdchar == 'q'
  276.         && !Recording
  277.         && !Exec_reg)
  278.         || ((ca.cmdchar == 'a' || ca.cmdchar == 'i')
  279.         && (oap->op_type != OP_NOP || VIsual_active)))
  280.     {
  281.     ++no_mapping;
  282.     ++allow_keys;        /* no mapping for nchar, but allow key codes */
  283. #ifdef USE_GUI
  284.     if (ca.cmdchar == 'r' && gui.in_use)
  285.     {
  286.         State = REPLACE;    /* pretend Replace mode, for cursor shape */
  287.         gui_upd_cursor_shape();
  288.     }
  289. #endif
  290.     ca.nchar = vgetc();
  291. #ifdef USE_GUI
  292.     State = NORMAL_BUSY;
  293. #endif
  294. #ifdef HAVE_LANGMAP
  295.     /* adjust chars > 127, except after tTfFr command */
  296.     LANGMAP_ADJUST(ca.nchar,
  297.                vim_strchr((char_u *)"tTfFr", ca.cmdchar) == NULL);
  298. #endif
  299. #ifdef RIGHTLEFT
  300.     /* adjust Hebrew mapped char */
  301.     if (p_hkmap && vim_strchr((char_u *)"tTfFr", ca.cmdchar) && KeyTyped)
  302.         ca.nchar = hkmap(ca.nchar);
  303. # ifdef FKMAP
  304.     /* adjust Farsi mapped char */
  305.     if (p_fkmap && strchr("tTfFr", ca.cmdchar) && KeyTyped)
  306.         ca.nchar = fkmap(ca.nchar);
  307. # endif
  308. #endif
  309.     --no_mapping;
  310.     --allow_keys;
  311. #ifdef SHOWCMD
  312.     need_flushbuf |= add_to_showcmd(ca.nchar);
  313. #endif
  314.     }
  315.  
  316. #ifdef SHOWCMD
  317.     /*
  318.      * Flush the showcmd characters onto the screen so we can see them while
  319.      * the command is being executed.  Only do this when the shown command was
  320.      * actually displayed, otherwise this will slow down a lot when executing
  321.      * mappings.
  322.      */
  323.     if (need_flushbuf)
  324.     out_flush();
  325. #endif
  326.  
  327.     State = NORMAL;
  328.     if (ca.nchar == ESC)
  329.     {
  330.     clearop(oap);
  331.     if (p_im && !restart_edit)
  332.         restart_edit = 'a';
  333.     goto normal_end;
  334.     }
  335.     msg_didout = FALSE;        /* don't scroll screen up for normal command */
  336.     msg_col = 0;
  337.     old_pos = curwin->w_cursor;        /* remember where cursor was */
  338.  
  339. #ifdef RIGHTLEFT
  340.     if (curwin->w_p_rl && KeyTyped)    /* invert horizontal operations */
  341.     switch (ca.cmdchar)
  342.     {
  343.         case 'l':        ca.cmdchar = 'h'; break;
  344.         case K_RIGHT:   ca.cmdchar = K_LEFT; break;
  345.         case 'h':        ca.cmdchar = 'l'; break;
  346.         case K_LEFT:    ca.cmdchar = K_RIGHT; break;
  347.         case '>':        ca.cmdchar = '<'; break;
  348.         case '<':        ca.cmdchar = '>'; break;
  349.     }
  350. #endif
  351.  
  352. /*
  353.  * Generally speaking, every command below should either clear any pending
  354.  * operator (with *clearop*()), or set the motion type variable
  355.  * oap->motion_type.
  356.  *
  357.  * When a cursor motion command is made, it is marked as being a character or
  358.  * line oriented motion.  Then, if an operator is in effect, the operation
  359.  * becomes character or line oriented accordingly.
  360.  */
  361. /*
  362.  * Variables available here:
  363.  * ca.cmdchar    command character
  364.  * ca.nchar    extra command character
  365.  * ca.count0    count before command (0 if no count given)
  366.  * ca.count1    count before command (1 if no count given)
  367.  * oap        Operator Arguments (same as ca.oap)
  368.  * flag        is FALSE, use as you like.
  369.  * dir        is FORWARD, use as you like.
  370.  */
  371.     switch (ca.cmdchar)
  372.     {
  373. /*
  374.  * 0: Macros
  375.  */
  376.     case 'q':        /* (stop) recording into a named register */
  377.     if (checkclearop(oap))
  378.         break;
  379.             /* command is ignored while executing a register */
  380.     if (!Exec_reg && do_record(ca.nchar) == FAIL)
  381.         clearopbeep(oap);
  382.     break;
  383.  
  384.     case '@':        /* execute a named register */
  385.     do_at(&ca);
  386.     break;
  387.  
  388. /*
  389.  * 1: Screen positioning commands
  390.  */
  391.     case Ctrl('D'):
  392.     case Ctrl('U'):
  393.     do_halfpage(&ca);
  394.     break;
  395.  
  396.     case Ctrl('B'):
  397.     case K_S_UP:
  398.     case K_PAGEUP:
  399.     case K_KPAGEUP:
  400.     dir = BACKWARD;
  401.  
  402.     case Ctrl('F'):
  403.     case K_S_DOWN:
  404.     case K_PAGEDOWN:
  405.     case K_KPAGEDOWN:
  406.     if (checkclearop(oap))
  407.         break;
  408.     (void)onepage(dir, ca.count1);
  409.     break;
  410.  
  411.     case Ctrl('E'):
  412.     flag = TRUE;
  413.     /* FALLTHROUGH */
  414.  
  415.     case Ctrl('Y'):
  416.     do_scroll_line(&ca, flag);
  417.     break;
  418.  
  419.     case 'z':
  420.     if (!checkclearop(oap))
  421.         do_zet(&ca);
  422.     break;
  423.  
  424. /*
  425.  * 2: Control commands
  426.  */
  427.     case ':':
  428.        do_colon(&ca);
  429.        break;
  430.  
  431.     case 'Q':
  432.     /*
  433.      * Ignore 'Q' in Visual mode, just give a beep.
  434.      */
  435.     if (VIsual_active)
  436.         vim_beep();
  437.     else if (!checkclearop(oap))
  438.         do_exmode();
  439.     break;
  440.  
  441.     case K_HELP:
  442.     case K_F1:
  443.     if (!checkclearopq(oap))
  444.         do_help(NULL);
  445.     break;
  446.  
  447.     case Ctrl('L'):
  448.     if (!checkclearop(oap))
  449.     {
  450. #if defined(__BEOS__) && !USE_THREAD_FOR_INPUT_WITH_TIMEOUT
  451.         /*
  452.          * Right now, the BeBox doesn't seem to have an easy way to detect
  453.          * window resizing, so we cheat and make the user detect it
  454.          * manually with CTRL-L instead
  455.          */
  456.         ui_get_winsize();
  457. #endif
  458.         update_screen(CLEAR);
  459.     }
  460.     break;
  461.  
  462.     case Ctrl('G'):
  463.     if (!checkclearop(oap))
  464.         /* print full name if count given or :cd used */
  465.         fileinfo((int)ca.count0, FALSE, FALSE);
  466.     break;
  467.  
  468.     case K_CCIRCM:        /* CTRL-^, short for ":e #" */
  469.     if (!checkclearopq(oap))
  470.         (void)buflist_getfile((int)ca.count0, (linenr_t)0,
  471.                         GETF_SETMARK|GETF_ALT, FALSE);
  472.     break;
  473.  
  474.     /*
  475.      * "ZZ": write if changed, and exit window
  476.      * "ZQ": quit window (Elvis compatible)
  477.      */
  478.     case 'Z':
  479.     if (!checkclearopq(oap))
  480.     {
  481.         if (ca.nchar == 'Z')
  482.         stuffReadbuff((char_u *)":x\n");
  483.         else if (ca.nchar == 'Q')
  484.         stuffReadbuff((char_u *)":q!\n");
  485.         else
  486.         clearopbeep(oap);
  487.     }
  488.     break;
  489.  
  490.     case 163:            /* the pound sign, '#' for English keyboards */
  491.     ca.cmdchar = '#';
  492.     /*FALLTHROUGH*/
  493.  
  494.     case Ctrl(']'):        /* :ta to current identifier */
  495.     case 'K':            /* run program for current identifier */
  496.     case '*':            /* / to current identifier or string */
  497.     case '#':            /* ? to current identifier or string */
  498.     do_ident(&ca, &searchbuff);
  499.     break;
  500.  
  501.     case Ctrl('T'):        /* backwards in tag stack */
  502.     if (!checkclearopq(oap))
  503.         do_tag((char_u *)"", DT_POP, (int)ca.count1, FALSE);
  504.     break;
  505.  
  506. /*
  507.  * Cursor motions
  508.  */
  509.     case 'G':
  510.     do_goto(oap, ca.count0 == 0 ? (long)curbuf->b_ml.ml_line_count
  511.                     : ca.count0);
  512.     break;
  513.  
  514.     case 'H':
  515.     case 'M':
  516.     case 'L':
  517.     do_scroll(&ca);
  518.     break;
  519.  
  520.     case K_RIGHT:
  521.     if (mod_mask & MOD_MASK_CTRL)
  522.     {
  523.         oap->inclusive = FALSE;
  524.         do_wordcmd(&ca, 1);
  525.         break;
  526.     }
  527.     case 'l':
  528.     case ' ':
  529.     do_right(&ca);
  530.     break;
  531.  
  532.     case K_LEFT:
  533.     if (mod_mask & MOD_MASK_CTRL)
  534.     {
  535.         do_bck_word(&ca, 1);
  536.         break;
  537.     }
  538.     case 'h':
  539.     case K_BS:
  540.     case Ctrl('H'):
  541.     dont_adjust_op_end = do_left(&ca);
  542.     break;
  543.  
  544.     case '-':
  545.     flag = TRUE;
  546.     /* FALLTHROUGH */
  547.  
  548.     case 'k':
  549.     case K_UP:
  550.     case Ctrl('P'):
  551.     oap->motion_type = MLINE;
  552.     if (cursor_up(ca.count1, oap->op_type == OP_NOP) == FAIL)
  553.         clearopbeep(oap);
  554.     else if (flag)
  555.         beginline(BL_WHITE | BL_FIX);
  556.     break;
  557.  
  558.     case '+':
  559.     case CR:
  560.     flag = TRUE;
  561.     /* FALLTHROUGH */
  562.  
  563.     case 'j':
  564.     case K_DOWN:
  565.     case Ctrl('N'):
  566.     case NL:
  567.     oap->motion_type = MLINE;
  568.     if (cursor_down(ca.count1, oap->op_type == OP_NOP) == FAIL)
  569.         clearopbeep(oap);
  570.     else if (flag)
  571.         beginline(BL_WHITE | BL_FIX);
  572.     break;
  573.  
  574.     /*
  575.      * This is a strange motion command that helps make operators more
  576.      * logical. It is actually implemented, but not documented in the
  577.      * real Vi. This motion command actually refers to "the current
  578.      * line". Commands like "dd" and "yy" are really an alternate form of
  579.      * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  580.      * lines.
  581.      */
  582.     case '_':
  583.     do_lineop(&ca);
  584.     break;
  585.  
  586.     case K_HOME:
  587.     case K_KHOME:
  588.     if ((mod_mask & MOD_MASK_CTRL))        /* CTRL-HOME = goto line 1 */
  589.     {
  590.         do_goto(oap, 1L);
  591.         break;
  592.     }
  593.     ca.count0 = 1;
  594.     /* FALLTHROUGH */
  595.  
  596.     case '|':
  597.     oap->motion_type = MCHAR;
  598.     oap->inclusive = FALSE;
  599.     beginline(0);
  600.     if (ca.count0 > 0)
  601.     {
  602.         coladvance((colnr_t)(ca.count0 - 1));
  603.         curwin->w_curswant = (colnr_t)(ca.count0 - 1);
  604.     }
  605.     else
  606.         curwin->w_curswant = 0;
  607.     /* keep curswant at the column where we wanted to go, not where
  608.         we ended; differs is line is too short */
  609.     curwin->w_set_curswant = FALSE;
  610.     break;
  611.  
  612.     /*
  613.      * Word Motions
  614.      */
  615.     case 'B':
  616.     type = 1;
  617.     /* FALLTHROUGH */
  618.  
  619.     case 'b':
  620.     case K_S_LEFT:
  621.     do_bck_word(&ca, type);
  622.     break;
  623.  
  624.     case 'E':
  625.     type = TRUE;
  626.     /* FALLTHROUGH */
  627.  
  628.     case 'e':
  629.     oap->inclusive = TRUE;
  630.     do_wordcmd(&ca, type);
  631.     break;
  632.  
  633.     case 'W':
  634.     type = TRUE;
  635.     /* FALLTHROUGH */
  636.  
  637.     case 'w':
  638.     case K_S_RIGHT:
  639.     oap->inclusive = FALSE;
  640.     do_wordcmd(&ca, type);
  641.     break;
  642.  
  643.     case K_END:
  644.     case K_KEND:
  645.     if ((mod_mask & MOD_MASK_CTRL))        /* CTRL-END = goto last line */
  646.         do_goto(oap, curbuf->b_ml.ml_line_count);
  647.     /* FALLTHROUGH */
  648.  
  649.     case '$':
  650.     oap->motion_type = MCHAR;
  651.     oap->inclusive = TRUE;
  652.     curwin->w_curswant = MAXCOL;            /* so we stay at the end */
  653.     if (cursor_down((long)(ca.count1 - 1), oap->op_type == OP_NOP) == FAIL)
  654.     {
  655.         clearopbeep(oap);
  656.         break;
  657.     }
  658.     break;
  659.  
  660.     case '^':
  661.     flag = BL_WHITE | BL_FIX;
  662.     /* FALLTHROUGH */
  663.  
  664.     case '0':
  665.     oap->motion_type = MCHAR;
  666.     oap->inclusive = FALSE;
  667.     beginline(flag);
  668.     break;
  669.  
  670. /*
  671.  * 4: Searches
  672.  */
  673.     case '?':
  674.     case '/':
  675.     do_normal_search(&ca, &searchbuff, FALSE);
  676.     break;
  677.  
  678.     case 'N':
  679.     flag = SEARCH_REV;
  680.  
  681.     case 'n':
  682.     oap->motion_type = MCHAR;
  683.     oap->inclusive = FALSE;
  684.     curwin->w_set_curswant = TRUE;
  685.     if (!do_search(oap, 0, NULL, ca.count1,
  686.           SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG | flag))
  687.         clearop(oap);
  688.  
  689.     /* "/$" will put the cursor after the end of the line, may need to
  690.      * correct that here */
  691.     adjust_cursor();
  692.     break;
  693.  
  694.     /*
  695.      * Character searches
  696.      */
  697.     case 'T':
  698.     dir = BACKWARD;
  699.     /* FALLTHROUGH */
  700.  
  701.     case 't':
  702.     do_csearch(&ca, dir, TRUE);
  703.     break;
  704.  
  705.     case 'F':
  706.     dir = BACKWARD;
  707.     /* FALLTHROUGH */
  708.  
  709.     case 'f':
  710.     do_csearch(&ca, dir, FALSE);
  711.     break;
  712.  
  713.     case ',':
  714.     flag = 1;
  715.     /* FALLTHROUGH */
  716.  
  717.     case ';':
  718.     /* ca.nchar == NUL, thus repeat previous search */
  719.     do_csearch(&ca, flag, FALSE);
  720.     break;
  721.  
  722.     /*
  723.      * section or C function searches
  724.      */
  725.     case '[':
  726.     dir = BACKWARD;
  727.     /* FALLTHROUGH */
  728.  
  729.     case ']':
  730.     do_brackets(&ca, dir);
  731.     break;
  732.  
  733.     case '%':
  734.     do_percent(&ca);
  735.     break;
  736.  
  737.     case '(':
  738.     dir = BACKWARD;
  739.     /* FALLTHROUGH */
  740.  
  741.     case ')':
  742.     oap->motion_type = MCHAR;
  743.     if (ca.cmdchar == ')')
  744.         oap->inclusive = FALSE;
  745.     else
  746.         oap->inclusive = TRUE;
  747.     curwin->w_set_curswant = TRUE;
  748.  
  749.     if (findsent(dir, ca.count1) == FAIL)
  750.         clearopbeep(oap);
  751.     break;
  752.  
  753.     case '{':
  754.     dir = BACKWARD;
  755.     /* FALLTHROUGH */
  756.  
  757.     case '}':
  758.     oap->motion_type = MCHAR;
  759.     oap->inclusive = FALSE;
  760.     curwin->w_set_curswant = TRUE;
  761.     if (!findpar(oap, dir, ca.count1, NUL, FALSE))
  762.         clearopbeep(oap);
  763.     break;
  764.  
  765. /*
  766.  * 5: Edits
  767.  */
  768.     case '.':            /* redo command */
  769.     if (!checkclearopq(oap))
  770.     {
  771.         /*
  772.          * if restart_edit is TRUE, the last but one command is repeated
  773.          * instead of the last command (inserting text). This is used for
  774.          * CTRL-O <.> in insert mode
  775.          */
  776.         if (start_redo(ca.count0, restart_edit && !arrow_used) == FAIL)
  777.         clearopbeep(oap);
  778.     }
  779.     break;
  780.  
  781.     case 'u':            /* undo */
  782.     if (VIsual_active ||
  783.              oap->op_type == vim_strchr(op_chars, 'u') - op_chars + 1)
  784.     {
  785.         do_operator(&ca);
  786.         break;
  787.     }
  788.     /* FALLTHROUGH */
  789.  
  790.     case K_UNDO:
  791.     if (!checkclearopq(oap))
  792.     {
  793.         u_undo((int)ca.count1);
  794.         curwin->w_set_curswant = TRUE;
  795.     }
  796.     break;
  797.  
  798.     case Ctrl('R'):    /* undo undo */
  799.     if (!checkclearopq(oap))
  800.     {
  801.         u_redo((int)ca.count1);
  802.         curwin->w_set_curswant = TRUE;
  803.     }
  804.     break;
  805.  
  806.     case 'U':            /* Undo line */
  807.     /* In visual mode and typing "gUU" triggers an operator */
  808.     if (VIsual_active ||
  809.              oap->op_type == vim_strchr(op_chars, 'U') - op_chars + 1)
  810.     {
  811.         do_operator(&ca);
  812.         break;
  813.     }
  814.     if (!checkclearopq(oap))
  815.     {
  816.         u_undoline();
  817.         curwin->w_set_curswant = TRUE;
  818.     }
  819.     break;
  820.  
  821.     case 'r':
  822.     if (VIsual_active)
  823.     {
  824.         ca.cmdchar = 'c';
  825.         do_operator(&ca);
  826.         break;
  827.     }
  828.     if (!checkclearop(oap))
  829.         command_busy = do_replace(&ca);
  830.     break;
  831.  
  832.     case 'J':
  833.     if (VIsual_active)    /* join the visual lines */
  834.     {
  835.         do_operator(&ca);
  836.         break;
  837.     }
  838.     if (!checkclearop(oap))
  839.     {
  840.         if (ca.count0 <= 1)
  841.         ca.count0 = 2;        /* default for join is two lines! */
  842.         if (curwin->w_cursor.lnum + ca.count0 - 1 >
  843.                            curbuf->b_ml.ml_line_count)
  844.         {
  845.         clearopbeep(oap);        /* beyond last line */
  846.         break;
  847.         }
  848.  
  849.         prep_redo_cmd(&ca);
  850.         do_do_join(ca.count0, TRUE, TRUE);
  851.     }
  852.     break;
  853.  
  854.     case 'P':
  855.     case 'p':
  856.     do_pput(&ca);
  857.     break;
  858.  
  859.     case Ctrl('A'):        /* add to number */
  860.     case Ctrl('X'):        /* subtract from number */
  861.     if (!checkclearopq(oap))
  862.     {
  863.         if (do_addsub((int)ca.cmdchar, ca.count1) == OK)
  864.         prep_redo_cmd(&ca);
  865.     }
  866.     break;
  867.  
  868. /*
  869.  * 6: Inserts
  870.  */
  871.     case 'A':
  872.     if (checkclearopq(oap))
  873.         break;
  874.     /* FALLTHROUGH */
  875.  
  876.     case 'a':
  877.     if (ca.cmdchar == 'a' && (oap->op_type != OP_NOP || VIsual_active))
  878. #ifdef TEXT_OBJECTS
  879.         do_object(&ca);    /* 'a' text object */
  880. #else
  881.         clearopbeep(oap);
  882. #endif
  883.     else
  884.     {
  885.         if (ca.cmdchar == 'A')
  886.         {
  887.         curwin->w_set_curswant = TRUE;
  888.         while (oneright() == OK)
  889.             ;
  890.         }
  891.  
  892.         if (u_save_cursor() == OK)
  893.         {
  894.         /* Works just like an 'i'nsert on the next character. */
  895.         if (!lineempty(curwin->w_cursor.lnum))
  896.             inc_cursor();
  897.         command_busy = edit(ca.cmdchar, FALSE, ca.count1);
  898.         }
  899.     }
  900.     break;
  901.  
  902.     case 'I':
  903.     if (checkclearopq(oap))
  904.         break;
  905.     beginline(BL_WHITE);
  906.     /* FALLTHROUGH */
  907.  
  908.     case 'i':
  909.     if (ca.cmdchar == 'i' && (oap->op_type != OP_NOP || VIsual_active))
  910.     {
  911. #ifdef TEXT_OBJECTS
  912.         do_object(&ca);    /* 'i'nner text object */
  913. #else
  914.         clearopbeep(oap);
  915. #endif
  916.         break;
  917.     }
  918.     /* FALLTHROUGH */
  919.  
  920.     case K_INS:
  921.     if (!checkclearopq(oap))
  922.     {
  923.         if (u_save_cursor() == OK)
  924.         command_busy = edit(ca.cmdchar, FALSE, ca.count1);
  925.     }
  926.     break;
  927.  
  928.     case 'o':
  929.     case 'O':
  930.     if (VIsual_active)  /* switch start and end of visual */
  931.         switch_visual(&ca);
  932.     else
  933.         command_busy = do_opencmd(&ca);
  934.     break;
  935.  
  936.     case 'R':
  937.     if (VIsual_active)
  938.     {
  939.         ca.cmdchar = 'c';
  940.         VIsual_mode = 'V';
  941.         do_operator(&ca);
  942.         break;
  943.     }
  944.     if (!checkclearopq(oap))
  945.     {
  946.         if (u_save_cursor() == OK)
  947.         command_busy = edit('R', FALSE, ca.count1);
  948.     }
  949.     break;
  950.  
  951. /*
  952.  * 7: Operators
  953.  */
  954.     case '~':        /* swap case */
  955.     /*
  956.      * if tilde is not an operator and Visual is off: swap case
  957.      * of a single character
  958.      */
  959.     if (       !p_to
  960.         && !VIsual_active
  961.         && oap->op_type != vim_strchr(op_chars, '~') - op_chars + 1)
  962.     {
  963.         do_swapchar(&ca);
  964.         break;
  965.     }
  966.     /*FALLTHROUGH*/
  967.  
  968.     case 'd':
  969.     case 'c':
  970.     case 'y':
  971.     case '>':
  972.     case '<':
  973.     case '!':
  974.     case '=':
  975.     do_operator(&ca);
  976.     break;
  977.  
  978. /*
  979.  * 8: Abbreviations
  980.  */
  981.  
  982.     case 'S':
  983.     case 's':
  984.     if (VIsual_active)    /* "vs" and "vS" are the same as "vc" */
  985.     {
  986.         if (ca.cmdchar == 'S')
  987.         VIsual_mode = 'V';
  988.         ca.cmdchar = 'c';
  989.         do_operator(&ca);
  990.         break;
  991.     }
  992.     /* FALLTHROUGH */
  993.     case K_DEL:
  994.     case 'Y':
  995.     case 'D':
  996.     case 'C':
  997.     case 'x':
  998.     case 'X':
  999.     if (ca.cmdchar == K_DEL)
  1000.         ca.cmdchar = 'x';        /* DEL key behaves like 'x' */
  1001.  
  1002.     /* with Visual these commands are operators */
  1003.     if (VIsual_active)
  1004.     {
  1005.         do_visop(&ca);
  1006.         break;
  1007.     }
  1008.     /* FALLTHROUGH */
  1009.  
  1010.     case '&':
  1011.     do_optrans(&ca);
  1012.     opnum = 0;
  1013.     break;
  1014.  
  1015. /*
  1016.  * 9: Marks
  1017.  */
  1018.  
  1019.     case 'm':
  1020.     if (!checkclearop(oap))
  1021.     {
  1022.         if (setmark(ca.nchar) == FAIL)
  1023.         clearopbeep(oap);
  1024.     }
  1025.     break;
  1026.  
  1027.     case '\'':
  1028.     flag = TRUE;
  1029.     /* FALLTHROUGH */
  1030.  
  1031.     case '`':
  1032.     do_gomark(&ca, flag);
  1033.     break;
  1034.  
  1035.     case Ctrl('O'):        /* goto older pcmark */
  1036.     ca.count1 = -ca.count1;
  1037.     /* FALLTHROUGH */
  1038.  
  1039.     case Ctrl('I'):        /* goto newer pcmark */
  1040.     do_pcmark(&ca);
  1041.     break;
  1042.  
  1043. /*
  1044.  * 10. Register name setting
  1045.  */
  1046.     case '"':
  1047.     do_regname(&ca, &opnum);
  1048.     break;
  1049.  
  1050. /*
  1051.  * 11. Visual
  1052.  */
  1053.     case 'v':
  1054.     case 'V':
  1055.     case Ctrl('V'):
  1056.     if (!checkclearop(oap))
  1057.         do_visual(&ca);
  1058.     break;
  1059.  
  1060. /*
  1061.  * 12. Suspend
  1062.  */
  1063.  
  1064.     case Ctrl('Z'):
  1065.     clearop(oap);
  1066.     if (VIsual_active)
  1067.         end_visual_mode();            /* stop Visual */
  1068.     stuffReadbuff((char_u *)":st\r");   /* with autowrite */
  1069.     break;
  1070.  
  1071. /*
  1072.  * 13. Window commands
  1073.  */
  1074.  
  1075.     case Ctrl('W'):
  1076.     if (!checkclearop(oap))
  1077.         do_window(ca.nchar, ca.count0);    /* everything is in window.c */
  1078.     break;
  1079.  
  1080. /*
  1081.  *   14. extended commands (starting with 'g')
  1082.  */
  1083.     case 'g':
  1084.     command_busy = do_g_cmd(&ca, &searchbuff);
  1085.     break;
  1086.  
  1087. /*
  1088.  * 15. mouse click
  1089.  */
  1090. #ifdef USE_MOUSE
  1091.     case K_MIDDLEMOUSE:
  1092.     case K_MIDDLEDRAG:
  1093.     case K_MIDDLERELEASE:
  1094.     case K_LEFTMOUSE:
  1095.     case K_LEFTDRAG:
  1096.     case K_LEFTRELEASE:
  1097.     case K_RIGHTMOUSE:
  1098.     case K_RIGHTDRAG:
  1099.     case K_RIGHTRELEASE:
  1100.     (void)do_mouse(oap, ca.cmdchar, BACKWARD, ca.count1, FALSE);
  1101.     break;
  1102.  
  1103.     case K_IGNORE:
  1104.     break;
  1105. #endif
  1106.  
  1107. #ifdef USE_GUI
  1108. /*
  1109.  * 16. scrollbar movement
  1110.  */
  1111.     case K_SCROLLBAR:
  1112.     if (oap->op_type != OP_NOP)
  1113.         clearopbeep(oap);
  1114.  
  1115.     /* Even if an operator was pending, we still want to scroll */
  1116.     gui_do_scroll();
  1117.     break;
  1118.  
  1119.     case K_HORIZ_SCROLLBAR:
  1120.     if (oap->op_type != OP_NOP)
  1121.         clearopbeep(oap);
  1122.  
  1123.     /* Even if an operator was pending, we still want to scroll */
  1124.     gui_do_horiz_scroll();
  1125.     break;
  1126. #endif
  1127.  
  1128. #ifdef FKMAP
  1129.       case K_F8:
  1130.       case K_F9:
  1131.     farsi_fkey(ca.cmdchar);
  1132.     break;
  1133. #endif
  1134.  
  1135. #ifdef USE_SNIFF
  1136.       case K_SNIFF:
  1137.     ProcessSniffRequests();
  1138.     break;
  1139. #endif
  1140.  
  1141. /*
  1142.  * 17. The end
  1143.  */
  1144.     case Ctrl('C'):
  1145.     restart_edit = 0;
  1146.     /*FALLTHROUGH*/
  1147.  
  1148.     case ESC:
  1149.     do_esc(&ca, opnum);
  1150.     break;
  1151.  
  1152.     default:            /* not a known command */
  1153.     clearopbeep(oap);
  1154.     break;
  1155.  
  1156.     }    /* end of switch on command character */
  1157.  
  1158. /*
  1159.  * if we didn't start or finish an operator, reset oap->regname, unless we
  1160.  * need it later.
  1161.  */
  1162.     if (!finish_op && !oap->op_type &&
  1163.                vim_strchr((char_u *)"\"DCYSsXx.", ca.cmdchar) == NULL)
  1164.     oap->regname = 0;
  1165.  
  1166. /*
  1167.  * If an operation is pending, handle it...
  1168.  */
  1169.     do_pending_operator(&ca, searchbuff,
  1170.                &command_busy, old_col, FALSE, dont_adjust_op_end);
  1171.  
  1172.     /*
  1173.      * Wait when a message is displayed that will be overwritten by the mode
  1174.      * message.
  1175.      * In Visual mode and with "^O" in Insert mode, a short message will be
  1176.      * overwritten by the mode message.  Wait a bit, until a key is hit.
  1177.      * In Visual mode, it's more important to keep the Visual area updated
  1178.      * than keeping a message (e.g. from a /pat search).
  1179.      * Only do this if the command was typed, not from a mapping.
  1180.      * Also wait a bit after an error message, e.g. for "^O:".
  1181.      * Don't redraw the screen, it would remove the message.
  1182.      */
  1183.     if (       ((p_smd
  1184.             && ((VIsual_active
  1185.                 && old_pos.lnum == curwin->w_cursor.lnum
  1186.                 && old_pos.col == curwin->w_cursor.col)
  1187.             || restart_edit)
  1188.             && (clear_cmdline
  1189.             || redraw_cmdline)
  1190.             && msg_didany
  1191.             && !msg_nowait
  1192.             && KeyTyped)
  1193.         || (restart_edit
  1194.             && !VIsual_active
  1195.             && (msg_scroll
  1196.             || emsg_on_display)))
  1197.         && oap->regname == 0
  1198.         && !command_busy
  1199.         && stuff_empty()
  1200.         && oap->op_type == OP_NOP)
  1201.     {
  1202.     setcursor();
  1203.     out_flush();
  1204.     if (msg_scroll || emsg_on_display)
  1205.         ui_delay(1000L, TRUE);    /* wait at least one second */
  1206.     ui_delay(3000L, FALSE);        /* wait up to three seconds */
  1207.  
  1208.     msg_scroll = FALSE;
  1209.     emsg_on_display = FALSE;
  1210.     }
  1211.  
  1212.     /*
  1213.      * Finish up after executing a Normal mode command.
  1214.      */
  1215. normal_end:
  1216.  
  1217.     /* Reset finish_op, in case it was set */
  1218. #ifdef USE_GUI
  1219.     c = finish_op;
  1220. #endif
  1221.     finish_op = FALSE;
  1222. #ifdef USE_GUI
  1223.     /* Redraw the cursor with another shape, if we were in Operator-pending
  1224.      * mode or did a replace command. */
  1225.     if (gui.in_use && ((c && !finish_op) || ca.cmdchar == 'r'))
  1226.     gui_upd_cursor_shape();
  1227. #endif
  1228.  
  1229. #ifdef SHOWCMD
  1230.     if (oap->op_type == OP_NOP && oap->regname == 0)
  1231.     clear_showcmd();
  1232. #endif
  1233.  
  1234.     /*
  1235.      * Update the other windows for the current buffer if modified has been
  1236.      * set in set_Changed() (This should be done more efficiently)
  1237.      */
  1238.     if (modified)
  1239.     {
  1240.     update_other_win();
  1241.     modified = FALSE;
  1242.     }
  1243.  
  1244.     checkpcmark();        /* check if we moved since setting pcmark */
  1245.  
  1246.     vim_free(searchbuff);
  1247.     /*
  1248.      * May restart edit(), if we got here with CTRL-O in Insert mode.
  1249.      */
  1250.     if (       restart_edit
  1251.         && oap->op_type == OP_NOP
  1252.         && !VIsual_active
  1253.         && !command_busy
  1254.         && stuff_empty()
  1255.         && oap->regname == 0)
  1256.     (void)edit(restart_edit, FALSE, 1L);
  1257. }
  1258.  
  1259. /*
  1260.  * Handle an operator after visual mode or when the movement is finished
  1261.  */
  1262.     void
  1263. do_pending_operator(cap, searchbuff,
  1264.               command_busy, old_col, gui_yank, dont_adjust_op_end)
  1265.     CMDARG        *cap;
  1266.     char_u        *searchbuff;
  1267.     int            *command_busy;
  1268.     int            old_col;
  1269.     int            gui_yank;        /* yanking visual area for GUI */
  1270.     int            dont_adjust_op_end;
  1271. {
  1272.     OPARG        *oap = cap->oap;
  1273.     FPOS        old_cursor;
  1274.     int            VIsual_was_active = VIsual_active;
  1275.     int            empty_region_error;
  1276.  
  1277.     /* The visual area is remembered for redo */
  1278.     static int        redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
  1279.     static linenr_t redo_VIsual_line_count;    /* number of lines */
  1280.     static colnr_t  redo_VIsual_col;        /* number of cols or end column */
  1281.     static long        redo_VIsual_count;        /* count for Visual operator */
  1282.  
  1283. #ifdef USE_CLIPBOARD
  1284.     /*
  1285.      * Yank the visual area into the GUI selection register before we operate
  1286.      * on it and lose it forever.  This could call do_pending_operator()
  1287.      * recursively, but that's OK because gui_yank will be TRUE for the
  1288.      * nested call.  Note also that we call clip_copy_selection() and not
  1289.      * clip_auto_select().  This is because even when 'autoselect' is not set,
  1290.      * if we operate on the text, eg by deleting it, then this is considered to
  1291.      * be an explicit request for it to be put in the global cut buffer, so we
  1292.      * always want to do it here. -- webb
  1293.      */
  1294.     if (clipboard.available && oap->op_type != OP_NOP &&
  1295.                   !gui_yank && VIsual_active && !redo_VIsual_busy)
  1296.     clip_copy_selection();
  1297. #endif
  1298.     old_cursor = curwin->w_cursor;
  1299.  
  1300.     /*
  1301.      * If an operation is pending, handle it...
  1302.      */
  1303.     if ((VIsual_active || finish_op) && oap->op_type != OP_NOP)
  1304.     {
  1305.     oap->is_VIsual = VIsual_active;
  1306.  
  1307.     /* only redo yank when 'y' flag is in 'cpoptions' */
  1308.     if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
  1309.         && !VIsual_active)
  1310.     {
  1311.         prep_redo(oap->regname, cap->count0, oap->op_prechar,
  1312.             op_chars[oap->op_type - 1], cap->cmdchar, cap->nchar);
  1313.         if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */
  1314.         {
  1315.         /*
  1316.          * If 'cpoptions' does not contain 'r', insert the search
  1317.          * pattern to really repeat the same command.
  1318.          */
  1319.         if (vim_strchr(p_cpo, CPO_REDO) == NULL)
  1320.             AppendToRedobuff(searchbuff);
  1321.         AppendToRedobuff(NL_STR);
  1322.         }
  1323.     }
  1324.  
  1325.     if (redo_VIsual_busy)
  1326.     {
  1327.         oap->start = curwin->w_cursor;
  1328.         curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
  1329.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1330.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1331.         VIsual_mode = redo_VIsual_mode;
  1332.         if (VIsual_mode == 'v')
  1333.         {
  1334.         if (redo_VIsual_line_count <= 1)
  1335.             curwin->w_cursor.col += redo_VIsual_col - 1;
  1336.         else
  1337.             curwin->w_cursor.col = redo_VIsual_col;
  1338.         }
  1339.         if (redo_VIsual_col == MAXCOL)
  1340.         {
  1341.         curwin->w_curswant = MAXCOL;
  1342.         coladvance(MAXCOL);
  1343.         }
  1344.         cap->count0 = redo_VIsual_count;
  1345.         if (redo_VIsual_count != 0)
  1346.         cap->count1 = redo_VIsual_count;
  1347.         else
  1348.         cap->count1 = 1;
  1349.     }
  1350.     else if (VIsual_active)
  1351.     {
  1352.         /* Save the current VIsual area for '< and '> marks, and "gv" */
  1353.         curbuf->b_visual_start = VIsual;
  1354.         curbuf->b_visual_end = curwin->w_cursor;
  1355.         curbuf->b_visual_mode = VIsual_mode;
  1356.  
  1357.         oap->start = VIsual;
  1358.         if (VIsual_mode == 'V')
  1359.         oap->start.col = 0;
  1360.     }
  1361.  
  1362.     /*
  1363.      * Set oap->start to the first position of the operated text, oap->end
  1364.      * to the end of the operated text.  w_cursor is equal to oap->start.
  1365.      */
  1366.     if (lt(oap->start, curwin->w_cursor))
  1367.     {
  1368.         oap->end = curwin->w_cursor;
  1369.         curwin->w_cursor = oap->start;
  1370.     }
  1371.     else
  1372.     {
  1373.         oap->end = oap->start;
  1374.         oap->start = curwin->w_cursor;
  1375.     }
  1376.     oap->line_count = oap->end.lnum - oap->start.lnum + 1;
  1377.  
  1378.     if (VIsual_active || redo_VIsual_busy)
  1379.     {
  1380.         if (VIsual_mode == Ctrl('V'))    /* block mode */
  1381.         {
  1382.         colnr_t        start, end;
  1383.  
  1384.         oap->block_mode = TRUE;
  1385.  
  1386.         getvcol(curwin, &(oap->start),
  1387.                       &oap->start_vcol, NULL, &oap->end_vcol);
  1388.         if (!redo_VIsual_busy)
  1389.         {
  1390.             getvcol(curwin, &(oap->end), &start, NULL, &end);
  1391.             if (start < oap->start_vcol)
  1392.             oap->start_vcol = start;
  1393.             if (end > oap->end_vcol)
  1394.             oap->end_vcol = end;
  1395.         }
  1396.  
  1397.         /* if '$' was used, get oap->end_vcol from longest line */
  1398.         if (curwin->w_curswant == MAXCOL)
  1399.         {
  1400.             curwin->w_cursor.col = MAXCOL;
  1401.             oap->end_vcol = 0;
  1402.             for (curwin->w_cursor.lnum = oap->start.lnum;
  1403.                 curwin->w_cursor.lnum <= oap->end.lnum;
  1404.                               ++curwin->w_cursor.lnum)
  1405.             {
  1406.             getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
  1407.             if (end > oap->end_vcol)
  1408.                 oap->end_vcol = end;
  1409.             }
  1410.         }
  1411.         else if (redo_VIsual_busy)
  1412.             oap->end_vcol = oap->start_vcol + redo_VIsual_col - 1;
  1413.         /*
  1414.          * Correct oap->end.col and oap->start.col to be the
  1415.          * upper-left and lower-right corner of the block area.
  1416.          */
  1417.         curwin->w_cursor.lnum = oap->end.lnum;
  1418.         coladvance(oap->end_vcol);
  1419.         oap->end = curwin->w_cursor;
  1420.         curwin->w_cursor = oap->start;
  1421.         coladvance(oap->start_vcol);
  1422.         oap->start = curwin->w_cursor;
  1423.         }
  1424.  
  1425.         if (!redo_VIsual_busy)
  1426.         {
  1427.         /*
  1428.          * Prepare to reselect and redo Visual: this is based on the
  1429.          * size of the Visual text
  1430.          */
  1431.         resel_VIsual_mode = VIsual_mode;
  1432.         if (curwin->w_curswant == MAXCOL)
  1433.             resel_VIsual_col = MAXCOL;
  1434.         else if (VIsual_mode == Ctrl('V'))
  1435.             resel_VIsual_col = oap->end_vcol - oap->start_vcol + 1;
  1436.         else if (oap->line_count > 1)
  1437.             resel_VIsual_col = oap->end.col;
  1438.         else
  1439.             resel_VIsual_col = oap->end.col - oap->start.col + 1;
  1440.         resel_VIsual_line_count = oap->line_count;
  1441.         }
  1442.  
  1443.         /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
  1444.         if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
  1445.             && oap->op_type != OP_COLON)
  1446.         {
  1447.         prep_redo(oap->regname, 0L, NUL, 'v', oap->op_prechar,
  1448.                           op_chars[oap->op_type - 1]);
  1449.         redo_VIsual_mode = resel_VIsual_mode;
  1450.         redo_VIsual_col = resel_VIsual_col;
  1451.         redo_VIsual_line_count = resel_VIsual_line_count;
  1452.         redo_VIsual_count = cap->count0;
  1453.         }
  1454.  
  1455.         /*
  1456.          * Mincl defaults to TRUE.
  1457.          * If op_end is on a NUL (empty line) oap->inclusive becomes FALSE
  1458.          * This makes "d}P" and "v}dP" work the same.
  1459.          */
  1460.         oap->inclusive = TRUE;
  1461.         if (VIsual_mode == 'V')
  1462.         oap->motion_type = MLINE;
  1463.         else
  1464.         {
  1465.         oap->motion_type = MCHAR;
  1466.         if (*ml_get_pos(&(oap->end)) == NUL)
  1467.             oap->inclusive = FALSE;
  1468.         }
  1469.  
  1470.         redo_VIsual_busy = FALSE;
  1471.         /*
  1472.          * Switch Visual off now, so screen updating does
  1473.          * not show inverted text when the screen is redrawn.
  1474.          * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
  1475.          * no screen redraw, so it is done here to remove the inverted
  1476.          * part.
  1477.          */
  1478.         if (!gui_yank)
  1479.         {
  1480.         VIsual_active = FALSE;
  1481. #ifdef USE_MOUSE
  1482.         setmouse();
  1483. #endif
  1484.         if (p_smd)
  1485.             clear_cmdline = TRUE;   /* unshow visual mode later */
  1486.         if (oap->op_type == OP_YANK || oap->op_type == OP_COLON ||
  1487.                              oap->op_type == OP_FILTER)
  1488.             update_curbuf(NOT_VALID);
  1489.         }
  1490.     }
  1491.  
  1492.     curwin->w_set_curswant = TRUE;
  1493.  
  1494.     /*
  1495.      * oap->empty is set when start and end are the same.  The inclusive
  1496.      * flag affects this too, unless yanking and the end is on a NUL.
  1497.      */
  1498.     oap->empty = (oap->motion_type == MCHAR
  1499.             && (!oap->inclusive
  1500.             || (oap->op_type == OP_YANK && gchar(&oap->end) == NUL))
  1501.             && equal(oap->start, oap->end));
  1502.     /*
  1503.      * For delete, change and yank, it's an error to operate on an
  1504.      * empty region, when 'E' inclucded in 'cpoptions' (Vi compatible).
  1505.      */
  1506.     empty_region_error = (oap->empty
  1507.                 && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
  1508.  
  1509.     /* Force a redraw when operating on an empty Visual region */
  1510.     if (VIsual_was_active && oap->empty)
  1511.         redraw_curbuf_later(NOT_VALID);
  1512.  
  1513.     /*
  1514.      * If the end of an operator is in column one while oap->motion_type is
  1515.      * MCHAR and oap->inclusive is FALSE, we put op_end after the last character
  1516.      * in the previous line. If op_start is on or before the first non-blank
  1517.      * in the line, the operator becomes linewise (strange, but that's the way
  1518.      * vi does it).
  1519.      */
  1520.     if (       oap->motion_type == MCHAR
  1521.         && oap->inclusive == FALSE
  1522.         && !dont_adjust_op_end
  1523.         && oap->end.col == 0
  1524.         && oap->line_count > 1)
  1525.     {
  1526.         oap->end_adjusted = TRUE;        /* remember that we did this */
  1527.         --oap->line_count;
  1528.         --oap->end.lnum;
  1529.         if (inindent(0))
  1530.         oap->motion_type = MLINE;
  1531.         else
  1532.         {
  1533.         oap->end.col = STRLEN(ml_get(oap->end.lnum));
  1534.         if (oap->end.col)
  1535.         {
  1536.             --oap->end.col;
  1537.             oap->inclusive = TRUE;
  1538.         }
  1539.         }
  1540.     }
  1541.     else
  1542.         oap->end_adjusted = FALSE;
  1543.  
  1544.     switch (oap->op_type)
  1545.     {
  1546.     case OP_LSHIFT:
  1547.     case OP_RSHIFT:
  1548.         op_shift(oap, TRUE, VIsual_was_active ? (int)cap->count1 : 1);
  1549.         break;
  1550.  
  1551.     case DO_JOIN:
  1552.         if (oap->line_count < 2)
  1553.         oap->line_count = 2;
  1554.         if (curwin->w_cursor.lnum + oap->line_count - 1 >
  1555.                            curbuf->b_ml.ml_line_count)
  1556.         beep_flush();
  1557.         else
  1558.         do_do_join(oap->line_count, TRUE, TRUE);
  1559.         break;
  1560.  
  1561.     case OP_DELETE:
  1562.         if (empty_region_error)
  1563.         vim_beep();
  1564.         else
  1565.         (void)op_delete(oap);
  1566.         break;
  1567.  
  1568.     case OP_YANK:
  1569.         if (empty_region_error)
  1570.         {
  1571.         if (!gui_yank)
  1572.             vim_beep();
  1573.         }
  1574.         else
  1575.         (void)op_yank(oap, FALSE, !gui_yank);
  1576.         break;
  1577.  
  1578.     case OP_CHANGE:
  1579.         if (empty_region_error)
  1580.         vim_beep();
  1581.         else
  1582.         *command_busy = op_change(oap);    /* will call edit() */
  1583.         break;
  1584.  
  1585.     case OP_FILTER:
  1586.         if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
  1587.         AppendToRedobuff((char_u *)"!\r");  /* use any last used !cmd */
  1588.         else
  1589.         bangredo = TRUE;    /* do_bang() will put cmd in redo buffer */
  1590.  
  1591.     case OP_INDENT:
  1592.     case OP_COLON:
  1593.  
  1594. #if defined(LISPINDENT) || defined(CINDENT)
  1595.         /*
  1596.          * If 'equalprg' is empty, do the indenting internally.
  1597.          */
  1598.         if (oap->op_type == OP_INDENT && *p_ep == NUL)
  1599.         {
  1600. # ifdef LISPINDENT
  1601.         if (curbuf->b_p_lisp)
  1602.         {
  1603.             op_reindent(oap, get_lisp_indent);
  1604.             break;
  1605.         }
  1606. # endif
  1607. # ifdef CINDENT
  1608.         op_reindent(oap, get_c_indent);
  1609.         break;
  1610. # endif
  1611.         }
  1612. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  1613.  
  1614.         op_colon(oap, VIsual_was_active);
  1615.         break;
  1616.  
  1617.     case OP_TILDE:
  1618.     case OP_UPPER:
  1619.     case OP_LOWER:
  1620.         if (empty_region_error)
  1621.         vim_beep();
  1622.         else
  1623.         op_tilde(oap);
  1624.         break;
  1625.  
  1626.     case OP_FORMAT:
  1627.     case OP_GFORMAT:
  1628.         if (*p_fp != NUL)
  1629.         op_colon(oap, VIsual_was_active);   /* use external command */
  1630.         else
  1631.         op_format(oap);                /* use internal function */
  1632.         break;
  1633.  
  1634.     default:
  1635.         clearopbeep(oap);
  1636.     }
  1637.     oap->op_prechar = NUL;
  1638.     if (!gui_yank)
  1639.     {
  1640.         /*
  1641.          * if 'sol' not set, go back to old column for some commands
  1642.          */
  1643.         if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
  1644.             && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
  1645.                         || oap->op_type == OP_DELETE))
  1646.         coladvance(curwin->w_curswant = old_col);
  1647.         oap->op_type = OP_NOP;
  1648.     }
  1649.     else
  1650.         curwin->w_cursor = old_cursor;
  1651.     oap->block_mode = FALSE;
  1652.     oap->regname = 0;
  1653.     }
  1654. }
  1655.  
  1656. /*
  1657.  * Handle indent and format operators and visual mode ":".
  1658.  */
  1659.     static void
  1660. op_colon(oap, VIsual_was_active)
  1661.     OPARG    *oap;
  1662.     int        VIsual_was_active;
  1663. {
  1664.     stuffcharReadbuff(':');
  1665.     if (VIsual_was_active)
  1666.     stuffReadbuff((char_u *)"'<,'>");
  1667.     else
  1668.     {
  1669.     /*
  1670.      * Make the range look nice, so it can be repeated.
  1671.      */
  1672.     if (oap->start.lnum == curwin->w_cursor.lnum)
  1673.         stuffcharReadbuff('.');
  1674.     else
  1675.         stuffnumReadbuff((long)oap->start.lnum);
  1676.     if (oap->end.lnum != oap->start.lnum)
  1677.     {
  1678.         stuffcharReadbuff(',');
  1679.         if (oap->end.lnum == curwin->w_cursor.lnum)
  1680.         stuffcharReadbuff('.');
  1681.         else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
  1682.         stuffcharReadbuff('$');
  1683.         else if (oap->start.lnum == curwin->w_cursor.lnum)
  1684.         {
  1685.         stuffReadbuff((char_u *)".+");
  1686.         stuffnumReadbuff((long)oap->line_count - 1);
  1687.         }
  1688.         else
  1689.         stuffnumReadbuff((long)oap->end.lnum);
  1690.     }
  1691.     }
  1692.     if (oap->op_type != OP_COLON)
  1693.     stuffReadbuff((char_u *)"!");
  1694.     if (oap->op_type == OP_INDENT)
  1695.     {
  1696. #ifndef CINDENT
  1697.     if (*p_ep == NUL)
  1698.         stuffReadbuff((char_u *)"indent");
  1699.     else
  1700. #endif
  1701.         stuffReadbuff(p_ep);
  1702.     stuffReadbuff((char_u *)"\n");
  1703.     }
  1704.     else if (oap->op_type == OP_FORMAT || oap->op_type == OP_GFORMAT)
  1705.     {
  1706.     if (*p_fp == NUL)
  1707.         stuffReadbuff((char_u *)"fmt");
  1708.     else
  1709.         stuffReadbuff(p_fp);
  1710.     stuffReadbuff((char_u *)"\n");
  1711.     }
  1712.  
  1713.     /*
  1714.      * do_cmdline() does the rest
  1715.      */
  1716. }
  1717.  
  1718. #ifdef USE_MOUSE
  1719. /*
  1720.  * Do the appropriate action for the current mouse click in the current mode.
  1721.  *
  1722.  * Normal Mode:
  1723.  * event     modi-    position      visual       change   action
  1724.  *         fier    cursor               window
  1725.  * left press      -    yes        end            yes
  1726.  * left press      C    yes        end            yes        "^]" (2)
  1727.  * left press      S    yes        end            yes        "*" (2)
  1728.  * left drag      -    yes    start if moved        no
  1729.  * left relse      -    yes    start if moved        no
  1730.  * middle press      -    yes     if not active        no        put register
  1731.  * middle press      -    yes     if active        no        yank and put
  1732.  * right press      -    yes    start or extend        yes
  1733.  * right press      S    yes    no change        yes        "#" (2)
  1734.  * right drag      -    yes    extend            no
  1735.  * right relse      -    yes    extend            no
  1736.  *
  1737.  * Insert or Replace Mode:
  1738.  * event     modi-    position      visual       change   action
  1739.  *         fier    cursor               window
  1740.  * left press      -    yes    (cannot be active)  yes
  1741.  * left press      C    yes    (cannot be active)  yes        "CTRL-O^]" (2)
  1742.  * left press      S    yes    (cannot be active)  yes        "CTRL-O*" (2)
  1743.  * left drag      -    yes    start or extend (1) no        CTRL-O (1)
  1744.  * left relse      -    yes    start or extend (1) no        CTRL-O (1)
  1745.  * middle press      -    no    (cannot be active)  no        put register
  1746.  * right press      -    yes    start or extend        yes        CTRL-O
  1747.  * right press      S    yes    (cannot be active)  yes        "CTRL-O#" (2)
  1748.  *
  1749.  * (1) only if mouse pointer moved since press
  1750.  * (2) only if click is in same buffer
  1751.  *
  1752.  * Return TRUE if start_arrow() should be called for edit mode.
  1753.  */
  1754.     int
  1755. do_mouse(oap, c, dir, count, fix_indent)
  1756.     OPARG   *oap;        /* operator argument, can be NULL */
  1757.     int        c;            /* K_LEFTMOUSE, etc */
  1758.     int        dir;        /* Direction to 'put' if necessary */
  1759.     long    count;
  1760.     int        fix_indent;        /* Do we fix indent for 'put' if necessary? */
  1761. {
  1762.     static FPOS    orig_cursor;
  1763.     static int    do_always = FALSE;    /* ignore 'mouse' setting next time */
  1764.     static int    got_click = FALSE;    /* got a click some time back */
  1765.  
  1766.     int        which_button;    /* MOUSE_LEFT, _MIDDLE or _RIGHT */
  1767.     int        is_click;        /* If FALSE it's a drag or release event */
  1768.     int        is_drag;        /* If TRUE it's a drag event */
  1769.     int        jump_flags = 0;    /* flags for jump_to_mouse() */
  1770.     FPOS    start_visual;
  1771.     FPOS    end_visual;
  1772.     int        diff;
  1773.     int        moved;        /* Has cursor moved? */
  1774.     int        in_status_line;    /* mouse in status line */
  1775.     int        c1, c2;
  1776.     int        VIsual_was_active = VIsual_active;
  1777.     int        regname;
  1778.  
  1779.     /*
  1780.      * When GUI is active, always recognize mouse events, otherwise:
  1781.      * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
  1782.      * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
  1783.      * - For command line and insert mode 'mouse' is checked before calling
  1784.      *     do_mouse().
  1785.      */
  1786.     if (do_always)
  1787.     do_always = FALSE;
  1788.     else
  1789. #ifdef USE_GUI
  1790.     if (!gui.in_use)
  1791. #endif
  1792.     {
  1793.         if (VIsual_active)
  1794.         {
  1795.         if (!mouse_has(MOUSE_VISUAL))
  1796.             return FALSE;
  1797.         }
  1798.         else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
  1799.         return FALSE;
  1800.     }
  1801.  
  1802.     which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
  1803.  
  1804.     /*
  1805.      * Ignore drag and release events if we didn't get a click.
  1806.      */
  1807.     if (is_click)
  1808.     got_click = TRUE;
  1809.     else
  1810.     {
  1811.     if (!got_click)            /* didn't get click, ignore */
  1812.         return FALSE;
  1813.     if (!is_drag)            /* release, reset got_click */
  1814.         got_click = FALSE;
  1815.     }
  1816.  
  1817.     /*
  1818.      * ALT is currently ignored
  1819.      */
  1820.     if ((mod_mask & MOD_MASK_ALT))
  1821.     return FALSE;
  1822.  
  1823.     /*
  1824.      * CTRL right mouse button does CTRL-T
  1825.      */
  1826.     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
  1827.     {
  1828.     if (State & INSERT)
  1829.         stuffcharReadbuff(Ctrl('O'));
  1830.     stuffcharReadbuff(Ctrl('T'));
  1831.     got_click = FALSE;        /* ignore drag&release now */
  1832.     return FALSE;
  1833.     }
  1834.  
  1835.     /*
  1836.      * CTRL only works with left mouse button
  1837.      */
  1838.     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
  1839.     return FALSE;
  1840.  
  1841.     /*
  1842.      * When a modifier is down, ignore drag and release events, as well as
  1843.      * multiple clicks and the middle mouse button.
  1844.      */
  1845.     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) &&
  1846.                 (!is_click || (mod_mask & MOD_MASK_MULTI_CLICK) ||
  1847.                         which_button == MOUSE_MIDDLE))
  1848.     return FALSE;
  1849.  
  1850.     /*
  1851.      * If the button press was used as the movement command for an operator
  1852.      * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
  1853.      * drag/release events.
  1854.      */
  1855.     if (!is_click && which_button == MOUSE_MIDDLE)
  1856.     return FALSE;
  1857.  
  1858.     if (oap != NULL)
  1859.     regname = oap->regname;
  1860.     else
  1861.     regname = 0;
  1862.  
  1863.     /*
  1864.      * Middle mouse button does a 'put' of the selected text
  1865.      */
  1866.     if (which_button == MOUSE_MIDDLE)
  1867.     {
  1868.     if (State == NORMAL)
  1869.     {
  1870.         /*
  1871.          * If an operator was pending, we don't know what the user wanted
  1872.          * to do. Go back to normal mode: Clear the operator and beep().
  1873.          */
  1874.         if (oap != NULL && oap->op_type != OP_NOP)
  1875.         {
  1876.         clearopbeep(oap);
  1877.         return FALSE;
  1878.         }
  1879.  
  1880.         /*
  1881.          * If visual was active, yank the highlighted text and put it
  1882.          * before the mouse pointer position.
  1883.          */
  1884.         if (VIsual_active)
  1885.         {
  1886.         stuffcharReadbuff('y');
  1887.         stuffcharReadbuff(K_MIDDLEMOUSE);
  1888.         do_always = TRUE;    /* ignore 'mouse' setting next time */
  1889.         return FALSE;
  1890.         }
  1891.         /*
  1892.          * The rest is below jump_to_mouse()
  1893.          */
  1894.     }
  1895.  
  1896.     /*
  1897.      * Middle click in insert mode doesn't move the mouse, just insert the
  1898.      * contents of a register.  '.' register is special, can't insert that
  1899.      * with do_put().
  1900.      */
  1901.     else if (State & INSERT)
  1902.     {
  1903.         if (regname == '.')
  1904.         insert_reg(regname, TRUE);
  1905.         else
  1906.         {
  1907. #ifdef USE_CLIPBOARD
  1908.         if (clipboard.available && regname == 0)
  1909.             regname = '*';
  1910. #endif
  1911.         if (State == REPLACE && !yank_register_mline(regname))
  1912.             insert_reg(regname, TRUE);
  1913.         else
  1914.         {
  1915.             do_put(regname, BACKWARD, 1L, fix_indent);
  1916.  
  1917.             /* Put cursor after the end of the just pasted text. */
  1918.             curwin->w_cursor = curbuf->b_op_end;
  1919.             if (gchar_cursor() != NUL)
  1920.             ++curwin->w_cursor.col;
  1921.  
  1922.             /* Repeat it with CTRL-R CTRL-R x.  Not exactly the same,
  1923.              * but mostly works fine. */
  1924.             AppendCharToRedobuff(Ctrl('R'));
  1925.             AppendCharToRedobuff(Ctrl('R'));
  1926.             AppendCharToRedobuff(regname == 0 ? '"' : regname);
  1927.         }
  1928.         }
  1929.         return FALSE;
  1930.     }
  1931.     else
  1932.         return FALSE;
  1933.     }
  1934.  
  1935.     if (!is_click)
  1936.     jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
  1937.  
  1938.     start_visual.lnum = 0;
  1939.  
  1940.     if ((State & (NORMAL | INSERT)) &&
  1941.                    !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
  1942.     {
  1943.     if (which_button == MOUSE_LEFT)
  1944.     {
  1945.         if (is_click)
  1946.         {
  1947.         /* stop Visual mode for a left click in a window, but not when
  1948.          * on a status line */
  1949.         if (VIsual_active)
  1950.             jump_flags |= MOUSE_MAY_STOP_VIS;
  1951.         }
  1952.         else
  1953.         jump_flags |= MOUSE_MAY_VIS;
  1954.     }
  1955.     else if (which_button == MOUSE_RIGHT)
  1956.     {
  1957.         if (is_click && VIsual_active)
  1958.         {
  1959.         /*
  1960.          * Remember the start and end of visual before moving the
  1961.          * cursor.
  1962.          */
  1963.         if (lt(curwin->w_cursor, VIsual))
  1964.         {
  1965.             start_visual = curwin->w_cursor;
  1966.             end_visual = VIsual;
  1967.         }
  1968.         else
  1969.         {
  1970.             start_visual = VIsual;
  1971.             end_visual = curwin->w_cursor;
  1972.         }
  1973.         }
  1974.         jump_flags |= MOUSE_MAY_VIS;
  1975.     }
  1976.     }
  1977.  
  1978.     /*
  1979.      * If an operator is pending, ignore all drags and releases until the
  1980.      * next mouse click.
  1981.      */
  1982.     if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
  1983.     {
  1984.     got_click = FALSE;
  1985.     oap->motion_type = MCHAR;
  1986.     }
  1987.  
  1988.     /*
  1989.      * Jump!
  1990.      */
  1991.     jump_flags = jump_to_mouse(jump_flags,
  1992.                       oap == NULL ? NULL : &(oap->inclusive));
  1993.     moved = (jump_flags & CURSOR_MOVED);
  1994.     in_status_line = ((jump_flags & IN_STATUS_LINE) == IN_STATUS_LINE);
  1995.  
  1996.     if (start_visual.lnum)        /* right click in visual mode */
  1997.     {
  1998.     /*
  1999.      * In Visual-block mode, divide the area in four, pick up the corner
  2000.      * that is in the quarter that the cursor is in.
  2001.      */
  2002.     if (VIsual_mode == Ctrl('V'))
  2003.     {
  2004.         colnr_t    leftcol, rightcol;
  2005.  
  2006.         getvcols(&start_visual, &end_visual, &leftcol, &rightcol);
  2007.         if (curwin->w_curswant > (leftcol + rightcol) / 2)
  2008.         end_visual.col = leftcol;
  2009.         else
  2010.         end_visual.col = rightcol;
  2011.         if (curwin->w_cursor.lnum <
  2012.                     (start_visual.lnum + end_visual.lnum) / 2)
  2013.         end_visual.lnum = end_visual.lnum;
  2014.         else
  2015.         end_visual.lnum = start_visual.lnum;
  2016.  
  2017.         /* move VIsual to the right column */
  2018.         start_visual = curwin->w_cursor;        /* save the cursor pos */
  2019.         curwin->w_cursor = end_visual;
  2020.         coladvance(end_visual.col);
  2021.         VIsual = curwin->w_cursor;
  2022.         curwin->w_cursor = start_visual;        /* restore the cursor */
  2023.     }
  2024.     else
  2025.     {
  2026.         /*
  2027.          * If the click is before the start of visual, change the start.
  2028.          * If the click is after the end of visual, change the end.  If
  2029.          * the click is inside the visual, change the closest side.
  2030.          */
  2031.         if (lt(curwin->w_cursor, start_visual))
  2032.         VIsual = end_visual;
  2033.         else if (lt(end_visual, curwin->w_cursor))
  2034.         VIsual = start_visual;
  2035.         else
  2036.         {
  2037.         /* In the same line, compare column number */
  2038.         if (end_visual.lnum == start_visual.lnum)
  2039.         {
  2040.             if (curwin->w_cursor.col - start_visual.col >
  2041.                     end_visual.col - curwin->w_cursor.col)
  2042.             VIsual = start_visual;
  2043.             else
  2044.             VIsual = end_visual;
  2045.         }
  2046.  
  2047.         /* In different lines, compare line number */
  2048.         else
  2049.         {
  2050.             diff = (curwin->w_cursor.lnum - start_visual.lnum) -
  2051.                 (end_visual.lnum - curwin->w_cursor.lnum);
  2052.  
  2053.             if (diff > 0)        /* closest to end */
  2054.             VIsual = start_visual;
  2055.             else if (diff < 0)    /* closest to start */
  2056.             VIsual = end_visual;
  2057.             else            /* in the middle line */
  2058.             {
  2059.             if (curwin->w_cursor.col <
  2060.                     (start_visual.col + end_visual.col) / 2)
  2061.                 VIsual = end_visual;
  2062.             else
  2063.                 VIsual = start_visual;
  2064.             }
  2065.         }
  2066.         }
  2067.     }
  2068.     }
  2069.     /*
  2070.      * If Visual mode started in insert mode, execute "CTRL-O"
  2071.      */
  2072.     else if ((State & INSERT) && VIsual_active)
  2073.     stuffcharReadbuff(Ctrl('O'));
  2074.  
  2075.     /*
  2076.      * When the cursor has moved in insert mode, and something was inserted,
  2077.      * and there are several windows, need to redraw.
  2078.      */
  2079.     if (moved && (State & INSERT) && modified && firstwin->w_next != NULL)
  2080.     {
  2081.     update_curbuf(NOT_VALID);
  2082.     modified = FALSE;
  2083.     }
  2084.  
  2085.     /*
  2086.      * Middle mouse click: Put text before cursor.
  2087.      */
  2088.     if (which_button == MOUSE_MIDDLE)
  2089.     {
  2090. #ifdef USE_CLIPBOARD
  2091.     if (clipboard.available && regname == 0)
  2092.         regname = '*';
  2093. #endif
  2094.     if (yank_register_mline(regname))
  2095.     {
  2096.         if (mouse_past_bottom)
  2097.         dir = FORWARD;
  2098.     }
  2099.     else if (mouse_past_eol)
  2100.         dir = FORWARD;
  2101.  
  2102.     if (fix_indent)
  2103.     {
  2104.         c1 = (dir == BACKWARD) ? '[' : ']';
  2105.         c2 = 'p';
  2106.     }
  2107.     else
  2108.     {
  2109.         c1 = (dir == FORWARD) ? 'p' : 'P';
  2110.         c2 = NUL;
  2111.     }
  2112.     prep_redo(regname, count, NUL, c1, c2, NUL);
  2113.  
  2114.     /*
  2115.      * Remember where the paste started, so in edit() Insstart can be set
  2116.      * to this position
  2117.      */
  2118.     if (restart_edit)
  2119.         where_paste_started = curwin->w_cursor;
  2120.     do_put(regname, dir, count, fix_indent);
  2121.  
  2122.     /* Put cursor at the end of the just pasted text. */
  2123.     curwin->w_cursor = curbuf->b_op_end;
  2124.     if (restart_edit && gchar_cursor() != NUL)
  2125.         ++curwin->w_cursor.col;        /* put cursor after the text */
  2126.     }
  2127.  
  2128.     /*
  2129.      * Ctrl-Mouse click (or double click in a help window) jumps to the tag
  2130.      * under the mouse pointer.
  2131.      */
  2132.     else if ((mod_mask & MOD_MASK_CTRL)
  2133.               || (curbuf->b_help && (mod_mask & MOD_MASK_2CLICK)))
  2134.     {
  2135.     if (State & INSERT)
  2136.         stuffcharReadbuff(Ctrl('O'));
  2137.     stuffcharReadbuff(Ctrl(']'));
  2138.     got_click = FALSE;        /* ignore drag&release now */
  2139.     }
  2140.  
  2141.     /*
  2142.      * Shift-Mouse click searches for the next occurrence of the word under
  2143.      * the mouse pointer
  2144.      */
  2145.     else if ((mod_mask & MOD_MASK_SHIFT))
  2146.     {
  2147.     if (State & INSERT)
  2148.         stuffcharReadbuff(Ctrl('O'));
  2149.     if (which_button == MOUSE_LEFT)
  2150.         stuffcharReadbuff('*');
  2151.     else    /* MOUSE_RIGHT */
  2152.         stuffcharReadbuff('#');
  2153.     }
  2154.  
  2155.     /* Handle double clicks, unless on status line */
  2156.     else if (in_status_line)
  2157.     ;
  2158.     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT)))
  2159.     {
  2160.     if (is_click || !VIsual_active)
  2161.     {
  2162.         if (VIsual_active)
  2163.         orig_cursor = VIsual;
  2164.         else
  2165.         {
  2166.         check_visual_highlight();
  2167.         VIsual = curwin->w_cursor;
  2168.         orig_cursor = VIsual;
  2169.         VIsual_active = TRUE;
  2170.         setmouse();
  2171.         if (p_smd)
  2172.             redraw_cmdline = TRUE;  /* show visual mode later */
  2173.         }
  2174.         if (mod_mask & MOD_MASK_2CLICK)
  2175.         VIsual_mode = 'v';
  2176.         else if (mod_mask & MOD_MASK_3CLICK)
  2177.         VIsual_mode = 'V';
  2178.         else if (mod_mask & MOD_MASK_4CLICK)
  2179.         VIsual_mode = Ctrl('V');
  2180.     }
  2181.     if (mod_mask & MOD_MASK_2CLICK)
  2182.     {
  2183.         if (lt(curwin->w_cursor, orig_cursor))
  2184.         {
  2185.         find_start_of_word(&curwin->w_cursor);
  2186.         find_end_of_word(&VIsual);
  2187.         }
  2188.         else
  2189.         {
  2190.         find_start_of_word(&VIsual);
  2191.         find_end_of_word(&curwin->w_cursor);
  2192.         }
  2193.         curwin->w_set_curswant = TRUE;
  2194.     }
  2195.     if (is_click)
  2196.         update_curbuf(NOT_VALID);        /* update the inversion */
  2197.     }
  2198.     else if (VIsual_active && VIsual_was_active != VIsual_active)
  2199.     VIsual_mode = 'v';
  2200.  
  2201.     return moved;
  2202. }
  2203.  
  2204.     static void
  2205. find_start_of_word(pos)
  2206.     FPOS    *pos;
  2207. {
  2208.     char_u  *ptr;
  2209.     int        cclass;
  2210.  
  2211.     ptr = ml_get(pos->lnum);
  2212.     cclass = get_mouse_class(ptr[pos->col]);
  2213.  
  2214.     /* Can't test pos->col >= 0 because pos->col is unsigned */
  2215.     while (pos->col > 0 && get_mouse_class(ptr[pos->col]) == cclass)
  2216.     pos->col--;
  2217.     if (pos->col != 0 || get_mouse_class(ptr[0]) != cclass)
  2218.     pos->col++;
  2219. }
  2220.  
  2221.     static void
  2222. find_end_of_word(pos)
  2223.     FPOS    *pos;
  2224. {
  2225.     char_u  *ptr;
  2226.     int        cclass;
  2227.  
  2228.     ptr = ml_get(pos->lnum);
  2229.     cclass = get_mouse_class(ptr[pos->col]);
  2230.     while (ptr[pos->col] && get_mouse_class(ptr[pos->col]) == cclass)
  2231.     pos->col++;
  2232.     if (pos->col)
  2233.     pos->col--;
  2234. }
  2235.  
  2236.     static int
  2237. get_mouse_class(c)
  2238.     int        c;
  2239. {
  2240.     if (c == ' ' || c == '\t')
  2241.     return ' ';
  2242.  
  2243.     if (vim_isIDc(c))
  2244.     return 'a';
  2245.  
  2246.     /*
  2247.      * There are a few special cases where we want certain combinations of
  2248.      * characters to be considered as a single word.  These are things like
  2249.      * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
  2250.      * character is in it's own class.
  2251.      */
  2252.     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
  2253.     return '=';
  2254.     return c;
  2255. }
  2256. #endif /* USE_MOUSE */
  2257.  
  2258. /*
  2259.  * Check if  highlighting for visual mode is possible, give a warning message
  2260.  * if not.
  2261.  */
  2262.     void
  2263. check_visual_highlight()
  2264. {
  2265.     static int        did_check = FALSE;
  2266.  
  2267.     if (!did_check && highlight_attr[HLF_V] == 0)
  2268.     MSG("Warning: terminal cannot highlight");
  2269.     did_check = TRUE;
  2270. }
  2271.  
  2272. /*
  2273.  * End visual mode.  If we are using the GUI, and autoselect is set, then
  2274.  * remember what was selected in case we need to paste it somewhere while we
  2275.  * still own the selection.  This function should ALWAYS be called to end
  2276.  * visual mode.
  2277.  */
  2278.     void
  2279. end_visual_mode()
  2280. {
  2281. #ifdef USE_CLIPBOARD
  2282.     if (clipboard.available)
  2283.     clip_auto_select();
  2284. #endif
  2285.     VIsual_active = FALSE;
  2286. #ifdef USE_MOUSE
  2287.     setmouse();
  2288. #endif
  2289.  
  2290.     /* Save the current VIsual area for '< and '> marks, and "gv" */
  2291.     curbuf->b_visual_start = VIsual;
  2292.     curbuf->b_visual_end = curwin->w_cursor;
  2293.     curbuf->b_visual_mode = VIsual_mode;
  2294.  
  2295.     if (p_smd)
  2296.     clear_cmdline = TRUE;        /* unshow visual mode later */
  2297. }
  2298.  
  2299. /*
  2300.  * Find the identifier under or to the right of the cursor.  If none is
  2301.  * found and find_type has FIND_STRING, then find any non-white string.  The
  2302.  * length of the string is returned, or zero if no string is found.  If a
  2303.  * string is found, a pointer to the string is put in *string, but note that
  2304.  * the caller must use the length returned as this string may not be NUL
  2305.  * terminated.
  2306.  */
  2307.     int
  2308. find_ident_under_cursor(string, find_type)
  2309.     char_u  **string;
  2310.     int        find_type;
  2311. {
  2312.     char_u  *ptr;
  2313.     int        col = 0;        /* init to shut up GCC */
  2314.     int        i;
  2315.  
  2316.     /*
  2317.      * if i == 0: try to find an identifier
  2318.      * if i == 1: try to find any string
  2319.      */
  2320.     ptr = ml_get_curline();
  2321.     for (i = (find_type & FIND_IDENT) ? 0 : 1;    i < 2; ++i)
  2322.     {
  2323.     /*
  2324.      * skip to start of identifier/string
  2325.      */
  2326.     col = curwin->w_cursor.col;
  2327.     while (ptr[col] != NUL &&
  2328.             (i == 0 ? !vim_iswordc(ptr[col]) : vim_iswhite(ptr[col])))
  2329.         ++col;
  2330.  
  2331.     /*
  2332.      * Back up to start of identifier/string. This doesn't match the
  2333.      * real vi but I like it a little better and it shouldn't bother
  2334.      * anyone.
  2335.      * When FIND_IDENT isn't defined, we backup until a blank.
  2336.      */
  2337.     while (col > 0 && (i == 0 ? vim_iswordc(ptr[col - 1]) :
  2338.             (!vim_iswhite(ptr[col - 1]) &&
  2339.            (!(find_type & FIND_IDENT) || !vim_iswordc(ptr[col - 1])))))
  2340.         --col;
  2341.  
  2342.     /*
  2343.      * if we don't want just any old string, or we've found an identifier,
  2344.      * stop searching.
  2345.      */
  2346.     if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
  2347.         break;
  2348.     }
  2349.     /*
  2350.      * didn't find an identifier or string
  2351.      */
  2352.     if (ptr[col] == NUL || (!vim_iswordc(ptr[col]) && i == 0))
  2353.     {
  2354.     if (find_type & FIND_STRING)
  2355.         EMSG("No string under cursor");
  2356.     else
  2357.         EMSG("No identifier under cursor");
  2358.     return 0;
  2359.     }
  2360.     ptr += col;
  2361.     *string = ptr;
  2362.     col = 0;
  2363.     while (i == 0 ? vim_iswordc(*ptr) : (*ptr != NUL && !vim_iswhite(*ptr)))
  2364.     {
  2365.     ++ptr;
  2366.     ++col;
  2367.     }
  2368.     return col;
  2369. }
  2370.  
  2371. /*
  2372.  * Prepare for redo of a normal command.
  2373.  */
  2374.     static void
  2375. prep_redo_cmd(cap)
  2376.     CMDARG  *cap;
  2377. {
  2378.     prep_redo(cap->oap->regname, cap->count0,
  2379.                       NUL, cap->cmdchar, NUL, cap->nchar);
  2380. }
  2381.  
  2382. /*
  2383.  * Prepare for redo of any command.
  2384.  */
  2385.     static void
  2386. prep_redo(regname, num, prechar, cmd, c, nchar)
  2387.     int        regname;
  2388.     long    num;
  2389.     int        prechar;
  2390.     int        cmd;
  2391.     int        c;
  2392.     int        nchar;
  2393. {
  2394.     ResetRedobuff();
  2395.     if (regname != 0)    /* yank from specified buffer */
  2396.     {
  2397.     AppendCharToRedobuff('\"');
  2398.     AppendCharToRedobuff(regname);
  2399.     }
  2400.     if (num)
  2401.     AppendNumberToRedobuff(num);
  2402.     if (prechar != NUL)
  2403.     AppendCharToRedobuff(prechar);
  2404.     AppendCharToRedobuff(cmd);
  2405.     if (c != NUL)
  2406.     AppendCharToRedobuff(c);
  2407.     if (nchar != NUL)
  2408.     AppendCharToRedobuff(nchar);
  2409. }
  2410.  
  2411. /*
  2412.  * check for operator active and clear it
  2413.  *
  2414.  * return TRUE if operator was active
  2415.  */
  2416.     static int
  2417. checkclearop(oap)
  2418.     OPARG    *oap;
  2419. {
  2420.     if (oap->op_type == OP_NOP)
  2421.     return FALSE;
  2422.     clearopbeep(oap);
  2423.     return TRUE;
  2424. }
  2425.  
  2426. /*
  2427.  * check for operator or Visual active and clear it
  2428.  *
  2429.  * return TRUE if operator was active
  2430.  */
  2431.     static int
  2432. checkclearopq(oap)
  2433.     OPARG    *oap;
  2434. {
  2435.     if (oap->op_type == OP_NOP && !VIsual_active)
  2436.     return FALSE;
  2437.     clearopbeep(oap);
  2438.     return TRUE;
  2439. }
  2440.  
  2441.     static void
  2442. clearop(oap)
  2443.     OPARG    *oap;
  2444. {
  2445.     oap->op_type = OP_NOP;
  2446.     oap->regname = 0;
  2447. }
  2448.  
  2449.     static void
  2450. clearopbeep(oap)
  2451.     OPARG    *oap;
  2452. {
  2453.     clearop(oap);
  2454.     beep_flush();
  2455. }
  2456.  
  2457. #ifdef SHOWCMD
  2458. /*
  2459.  * Routines for displaying a partly typed command
  2460.  */
  2461.  
  2462. static char_u    showcmd_buf[SHOWCMD_COLS + 1];
  2463. static char_u    old_showcmd_buf[SHOWCMD_COLS + 1];  /* For push_showcmd() */
  2464. static int    showcmd_is_clear = TRUE;
  2465.  
  2466. static void display_showcmd __ARGS((void));
  2467.  
  2468.     void
  2469. clear_showcmd()
  2470. {
  2471.     if (!p_sc)
  2472.     return;
  2473.  
  2474.     showcmd_buf[0] = NUL;
  2475.  
  2476.     /*
  2477.      * Don't actually display something if there is nothing to clear.
  2478.      */
  2479.     if (showcmd_is_clear)
  2480.     return;
  2481.  
  2482.     display_showcmd();
  2483. }
  2484.  
  2485. /*
  2486.  * Add 'c' to string of shown command chars.
  2487.  * Return TRUE if output has been written (and setcursor() has been called).
  2488.  */
  2489.     int
  2490. add_to_showcmd(c)
  2491.     int        c;
  2492. {
  2493.     char_u  *p;
  2494.     int        old_len;
  2495.     int        extra_len;
  2496.     int        overflow;
  2497.     int        i;
  2498.     static int        ignore[] =
  2499.            {K_SCROLLBAR, K_HORIZ_SCROLLBAR, K_IGNORE,
  2500.         K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
  2501.         K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE,
  2502.         K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
  2503.         0};
  2504.  
  2505.     if (!p_sc)
  2506.     return FALSE;
  2507.  
  2508.     /* Ignore keys that are scrollbar updates and mouse clicks */
  2509.     for (i = 0; ignore[i]; ++i)
  2510.     if (ignore[i] == c)
  2511.         return FALSE;
  2512.  
  2513.     p = transchar(c);
  2514.     old_len = STRLEN(showcmd_buf);
  2515.     extra_len = STRLEN(p);
  2516.     overflow = old_len + extra_len - SHOWCMD_COLS;
  2517.     if (overflow > 0)
  2518.     STRCPY(showcmd_buf, showcmd_buf + overflow);
  2519.     STRCAT(showcmd_buf, p);
  2520.  
  2521.     if (char_avail())
  2522.     return FALSE;
  2523.  
  2524.     display_showcmd();
  2525.  
  2526.     return TRUE;
  2527. }
  2528.  
  2529.     void
  2530. add_to_showcmd_c(c)
  2531.     int        c;
  2532. {
  2533.     if (!add_to_showcmd(c))
  2534.     setcursor();
  2535. }
  2536.  
  2537. /*
  2538.  * Delete 'len' characters from the end of the shown command.
  2539.  */
  2540.     static void
  2541. del_from_showcmd(len)
  2542.     int        len;
  2543. {
  2544.     int        old_len;
  2545.  
  2546.     if (!p_sc)
  2547.     return;
  2548.  
  2549.     old_len = STRLEN(showcmd_buf);
  2550.     if (len > old_len)
  2551.     len = old_len;
  2552.     showcmd_buf[old_len - len] = NUL;
  2553.  
  2554.     if (!char_avail())
  2555.     display_showcmd();
  2556. }
  2557.  
  2558.     void
  2559. push_showcmd()
  2560. {
  2561.     if (p_sc)
  2562.     STRCPY(old_showcmd_buf, showcmd_buf);
  2563. }
  2564.  
  2565.     void
  2566. pop_showcmd()
  2567. {
  2568.     if (!p_sc)
  2569.     return;
  2570.  
  2571.     STRCPY(showcmd_buf, old_showcmd_buf);
  2572.  
  2573.     display_showcmd();
  2574. }
  2575.  
  2576.     static void
  2577. display_showcmd()
  2578. {
  2579.     int        len;
  2580.  
  2581.     cursor_off();
  2582.  
  2583.     len = STRLEN(showcmd_buf);
  2584.     if (len == 0)
  2585.     showcmd_is_clear = TRUE;
  2586.     else
  2587.     {
  2588.     screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0);
  2589.     showcmd_is_clear = FALSE;
  2590.     }
  2591.  
  2592.     /*
  2593.      * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
  2594.      */
  2595.     screen_puts((char_u *)"          " + len, (int)Rows - 1, sc_col + len, 0);
  2596.  
  2597.     setcursor();        /* put cursor back where it belongs */
  2598. }
  2599. #endif
  2600.  
  2601. /*
  2602.  * Implementation of "gd" and "gD" command.
  2603.  */
  2604.     static void
  2605. do_gd(oap, nchar)
  2606.     OPARG   *oap;
  2607.     int        nchar;
  2608. {
  2609.     int        len;
  2610.     char_u    *pat;
  2611.     FPOS    old_pos;
  2612.     int        t;
  2613.     int        save_p_ws;
  2614.     int        save_p_scs;
  2615.     char_u    *ptr;
  2616.  
  2617.     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
  2618.                            (pat = alloc(len + 5)) == NULL)
  2619.     {
  2620.     clearopbeep(oap);
  2621.     return;
  2622.     }
  2623.     sprintf((char *)pat, vim_iswordc(*ptr) ? "\\<%.*s\\>" :
  2624.         "%.*s", len, ptr);
  2625.     old_pos = curwin->w_cursor;
  2626.     save_p_ws = p_ws;
  2627.     save_p_scs = p_scs;
  2628.     p_ws = FALSE;    /* don't wrap around end of file now */
  2629.     p_scs = FALSE;    /* don't switch ignorecase off now */
  2630.     fo_do_comments = TRUE;
  2631.  
  2632.     /*
  2633.      * Search back for the end of the previous function.
  2634.      * If this fails, and with "gD", go to line 1.
  2635.      * Search forward for the identifier, ignore comment lines.
  2636.      */
  2637.     if (nchar == 'D' || !findpar(oap, BACKWARD, 1L, '}', FALSE))
  2638.     {
  2639.     setpcmark();            /* Set in findpar() otherwise */
  2640.     curwin->w_cursor.lnum = 1;
  2641.     }
  2642.  
  2643.     while ((t = searchit(curbuf, &curwin->w_cursor, FORWARD, pat, 1L, 0,
  2644.         RE_LAST)) == OK &&
  2645.         get_leader_len(ml_get_curline(), NULL) &&
  2646.         old_pos.lnum > curwin->w_cursor.lnum)
  2647.     ++curwin->w_cursor.lnum;
  2648.     if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
  2649.     {
  2650.     clearopbeep(oap);
  2651.     curwin->w_cursor = old_pos;
  2652.     }
  2653.     else
  2654.     curwin->w_set_curswant = TRUE;
  2655.  
  2656.     vim_free(pat);
  2657.     p_ws = save_p_ws;
  2658.     p_scs = save_p_scs;
  2659.     fo_do_comments = FALSE;
  2660. }
  2661.  
  2662. /*
  2663.  * screengo() --
  2664.  *
  2665.  * move 'dist' lines in direction 'dir', counting lines by *screen*
  2666.  * lines rather than lines in the file
  2667.  * 'dist' must be positive.
  2668.  *
  2669.  * return OK if able to move cursor, FAIL otherwise.
  2670.  */
  2671.     static int
  2672. screengo(oap, dir, dist)
  2673.     OPARG   *oap;
  2674.     int        dir;
  2675.     long    dist;
  2676. {
  2677.     int        linelen = linetabsize(ml_get_curline());
  2678.     int        retval = OK;
  2679.     int        atend = FALSE;
  2680.     int        n;
  2681.  
  2682.     oap->motion_type = MCHAR;
  2683.     oap->inclusive = FALSE;
  2684.  
  2685.     /*
  2686.      * Instead of sticking at the last character of the line in the file we
  2687.      * try to stick in the last column of the screen
  2688.      */
  2689.     if (curwin->w_curswant == MAXCOL)
  2690.     {
  2691.     atend = TRUE;
  2692.     validate_virtcol();
  2693.     curwin->w_curswant = ((curwin->w_virtcol +
  2694.                (curwin->w_p_nu ? 8 : 0)) / Columns + 1) * Columns - 1;
  2695.     if (curwin->w_p_nu && curwin->w_curswant > 8)
  2696.         curwin->w_curswant -= 8;
  2697.     }
  2698.     else
  2699.     while (curwin->w_curswant >= (colnr_t)(linelen + Columns))
  2700.         curwin->w_curswant -= Columns;
  2701.  
  2702.     while (dist--)
  2703.     {
  2704.     if (dir == BACKWARD)
  2705.     {
  2706.                         /* move back within line */
  2707.         if ((long)curwin->w_curswant >= Columns)
  2708.         curwin->w_curswant -= Columns;
  2709.         else                /* to previous line */
  2710.         {
  2711.         if (curwin->w_cursor.lnum == 1)
  2712.         {
  2713.             retval = FAIL;
  2714.             break;
  2715.         }
  2716.         --curwin->w_cursor.lnum;
  2717.         linelen = linetabsize(ml_get_curline());
  2718.         n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns)
  2719.                                     * Columns;
  2720.         if (curwin->w_p_nu &&
  2721.                  (long)curwin->w_curswant >= Columns - 8 && n)
  2722.             n -= Columns;
  2723.         curwin->w_curswant += n;
  2724.         }
  2725.     }
  2726.     else /* dir == FORWARD */
  2727.     {
  2728.         n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns) * Columns;
  2729.         if (curwin->w_p_nu && n > 8)
  2730.         n -= 8;
  2731.                         /* move forward within line */
  2732.         if (curwin->w_curswant < (colnr_t)n)
  2733.         curwin->w_curswant += Columns;
  2734.         else                /* to next line */
  2735.         {
  2736.         if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  2737.         {
  2738.             retval = FAIL;
  2739.             break;
  2740.         }
  2741.         curwin->w_cursor.lnum++;
  2742.         linelen = linetabsize(ml_get_curline());
  2743.         curwin->w_curswant %= Columns;
  2744.         }
  2745.     }
  2746.     }
  2747.     coladvance(curwin->w_curswant);
  2748.     if (atend)
  2749.     curwin->w_curswant = MAXCOL;        /* stick in the last column */
  2750.  
  2751.     return retval;
  2752. }
  2753.  
  2754. /*
  2755.  * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
  2756.  */
  2757.     static void
  2758. do_scroll_line(cap, is_ctrl_e)
  2759.     CMDARG  *cap;
  2760.     int        is_ctrl_e;        /* TRUE for CTRL-E command */
  2761. {
  2762.     linenr_t        prev_topline = curwin->w_topline;
  2763.  
  2764.     if (checkclearop(cap->oap))
  2765.     return;
  2766.     if (is_ctrl_e)
  2767.     scrollup(cap->count1);
  2768.     else
  2769.     scrolldown(cap->count1);
  2770.     if (p_so)
  2771.     {
  2772.     cursor_correct();
  2773.     update_topline();
  2774.     /* If moved back to where we were, at least move the cursor, otherwise
  2775.      * we get stuck at one position.  Don't move the cursor up if the
  2776.      * first line of the buffer is already on the screen */
  2777.     if (curwin->w_topline == prev_topline)
  2778.     {
  2779.         if (is_ctrl_e)
  2780.         cursor_down(1L, FALSE);
  2781.         else if (prev_topline != 1L)
  2782.         cursor_up(1L, FALSE);
  2783.     }
  2784.     }
  2785.     coladvance(curwin->w_curswant);
  2786.     update_screen(VALID);
  2787. }
  2788.  
  2789.     static void
  2790. do_zet(cap)
  2791.     CMDARG  *cap;
  2792. {
  2793.     long    n;
  2794.     colnr_t    col;
  2795.     int        nchar = cap->nchar;
  2796.  
  2797.  
  2798.     if (vim_isdigit(nchar))
  2799.     {
  2800.     n = nchar - '0';
  2801.     for (;;)
  2802.     {
  2803. #ifdef USE_GUI_WIN32
  2804.         dont_scroll = TRUE;        /* disallow scrolling here */
  2805. #endif
  2806.         ++no_mapping;
  2807.         ++allow_keys;   /* no mapping for nchar, but allow key codes */
  2808.         nchar = vgetc();
  2809. #ifdef HAVE_LANGMAP
  2810.         LANGMAP_ADJUST(nchar, TRUE);
  2811. #endif
  2812.         --no_mapping;
  2813.         --allow_keys;
  2814. #ifdef SHOWCMD
  2815.         (void)add_to_showcmd(nchar);
  2816. #endif
  2817.         if (nchar == K_DEL)
  2818.         n /= 10;
  2819.         else if (vim_isdigit(nchar))
  2820.         n = n * 10 + (nchar - '0');
  2821.         else if (nchar == CR)
  2822.         {
  2823.         win_setheight((int)n);
  2824.         break;
  2825.         }
  2826.         else if (nchar == 'l' || nchar == 'h' ||
  2827.                       nchar == K_LEFT || nchar == K_RIGHT)
  2828.         {
  2829.         cap->count1 = n ? n * cap->count1 : cap->count1;
  2830.         goto dozet;
  2831.         }
  2832.         else
  2833.         {
  2834.         clearopbeep(cap->oap);
  2835.         break;
  2836.         }
  2837.     }
  2838.     cap->oap->op_type = OP_NOP;
  2839.     return;
  2840.     }
  2841. dozet:
  2842.     /*
  2843.      * If line number given, set cursor, except for "zh", "zl", "ze" and
  2844.      * "zs"
  2845.      */
  2846.     if (       vim_strchr((char_u *)"hles", nchar) == NULL
  2847.         && nchar != K_LEFT
  2848.         && nchar != K_RIGHT
  2849.         && cap->count0
  2850.         && cap->count0 != curwin->w_cursor.lnum)
  2851.     {
  2852.     setpcmark();
  2853.     if (cap->count0 > curbuf->b_ml.ml_line_count)
  2854.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2855.     else
  2856.         curwin->w_cursor.lnum = cap->count0;
  2857.     }
  2858.  
  2859.     switch (nchar)
  2860.     {
  2861.     case NL:            /* put curwin->w_cursor at top of screen */
  2862.     case CR:
  2863.     beginline(BL_WHITE | BL_FIX);
  2864.     /* FALLTHROUGH */
  2865.     case 't':
  2866.     scroll_cursor_top(0, TRUE);
  2867.     break;
  2868.  
  2869.     case '.':        /* put curwin->w_cursor in middle of screen */
  2870.     beginline(BL_WHITE | BL_FIX);
  2871.     /* FALLTHROUGH */
  2872.     case 'z':
  2873.     scroll_cursor_halfway(TRUE);
  2874.     break;
  2875.  
  2876.     case '-':        /* put curwin->w_cursor at bottom of screen */
  2877.     beginline(BL_WHITE | BL_FIX);
  2878.     /* FALLTHROUGH */
  2879.     case 'b':
  2880.     scroll_cursor_bot(0, TRUE);
  2881.     break;
  2882.  
  2883.     /* "zh" - scroll screen to the right */
  2884.     case 'h':
  2885.     case K_LEFT:
  2886.     if (!curwin->w_p_wrap)
  2887.     {
  2888.         if ((colnr_t)cap->count1 > curwin->w_leftcol)
  2889.         curwin->w_leftcol = 0;
  2890.         else
  2891.         curwin->w_leftcol -= (colnr_t)cap->count1;
  2892.         leftcol_changed();
  2893.     }
  2894.     break;
  2895.  
  2896.     /* "zl" - scroll screen to the left */
  2897.     case 'l':
  2898.     case K_RIGHT:
  2899.     if (!curwin->w_p_wrap)
  2900.     {
  2901.         /* scroll the window left */
  2902.         curwin->w_leftcol += (colnr_t)cap->count1;
  2903.         leftcol_changed();
  2904.     }
  2905.     break;
  2906.  
  2907.     /* "zs" - scroll screen, cursor at the start */
  2908.     case 's':
  2909.     if (!curwin->w_p_wrap)
  2910.     {
  2911.         getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
  2912.         curwin->w_leftcol = col;
  2913.         redraw_later(NOT_VALID);
  2914.     }
  2915.     break;
  2916.  
  2917.     /* "ze" - scroll screen, cursor at the end */
  2918.     case 'e':
  2919.     if (!curwin->w_p_wrap)
  2920.     {
  2921.         getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
  2922.         if ((long)col < Columns)
  2923.         curwin->w_leftcol = 0;
  2924.         else
  2925.         curwin->w_leftcol = col - Columns + 1;
  2926.         redraw_later(NOT_VALID);
  2927.     }
  2928.     break;
  2929.  
  2930.     case Ctrl('S'): /* ignore CTRL-S and CTRL-Q to avoid problems */
  2931.     case Ctrl('Q'): /* with terminals that use xon/xoff */
  2932.     break;
  2933.  
  2934.     default:
  2935.     clearopbeep(cap->oap);
  2936.     }
  2937.     update_screen(VALID);
  2938. }
  2939.  
  2940. /*
  2941.  * Handle a ":" command.
  2942.  */
  2943.     static void
  2944. do_colon(cap)
  2945.     CMDARG  *cap;
  2946. {
  2947.     int        old_p_im;
  2948.  
  2949.     if (VIsual_active)
  2950.     do_operator(cap);
  2951.     else if (!checkclearop(cap->oap))
  2952.     {
  2953.     /* translate "count:" into ":.,.+(count - 1)" */
  2954.     if (cap->count0)
  2955.     {
  2956.         stuffcharReadbuff('.');
  2957.         if (cap->count0 > 1)
  2958.         {
  2959.         stuffReadbuff((char_u *)",.+");
  2960.         stuffnumReadbuff((long)cap->count0 - 1L);
  2961.         }
  2962.     }
  2963.  
  2964.     /* When typing, don't type below an old message */
  2965.     if (KeyTyped)
  2966.         compute_cmdrow();
  2967.  
  2968.     old_p_im = p_im;
  2969.  
  2970.     /* get a command line and execute it */
  2971.     do_cmdline(NULL, getexline, NULL, 0);
  2972.  
  2973.     /* If 'insertmode' changed, enter or exit Insert mode */
  2974.     if (p_im != old_p_im)
  2975.     {
  2976.         if (p_im)
  2977.         restart_edit = 'i';
  2978.         else
  2979.         restart_edit = 0;
  2980.     }
  2981.     }
  2982. }
  2983.  
  2984. /*
  2985.  * Handle the commands that use the word under the cursor.
  2986.  *
  2987.  * Returns TRUE for "*" and "#" commands, indicating that the next search
  2988.  * should not set the pcmark.
  2989.  */
  2990.     static void
  2991. do_ident(cap, searchp)
  2992.     CMDARG    *cap;
  2993.     char_u    **searchp;
  2994. {
  2995.     char_u    *ptr = NULL;
  2996.     int        n = 0;        /* init for GCC */
  2997.     int        cmdchar;
  2998.     int        g_cmd;        /* "g" command */
  2999.     char_u    *aux_ptr;
  3000.  
  3001.     if (cap->cmdchar == 'g')    /* "g*", "g#", "g]" and "gCTRL-]" */
  3002.     {
  3003.     cmdchar = cap->nchar;
  3004.     g_cmd = TRUE;
  3005.     }
  3006.     else
  3007.     {
  3008.     cmdchar = cap->cmdchar;
  3009.     g_cmd = FALSE;
  3010.     }
  3011.  
  3012.     /*
  3013.      * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
  3014.      */
  3015.     if (cmdchar == ']' || cmdchar == Ctrl(']') || cmdchar == 'K')
  3016.     {
  3017.     if (VIsual_active)    /* :ta to visual highlighted text */
  3018.     {
  3019.         if (VIsual.lnum != curwin->w_cursor.lnum)
  3020.         {
  3021.         clearopbeep(cap->oap);
  3022.         return;
  3023.         }
  3024.         if (lt(curwin->w_cursor, VIsual))
  3025.         {
  3026.         ptr = ml_get_pos(&curwin->w_cursor);
  3027.         n = VIsual.col - curwin->w_cursor.col + 1;
  3028.         }
  3029.         else
  3030.         {
  3031.         ptr = ml_get_pos(&VIsual);
  3032.         n = curwin->w_cursor.col - VIsual.col + 1;
  3033.         }
  3034.         end_visual_mode();
  3035.         ++RedrawingDisabled;
  3036.         update_curbuf(NOT_VALID);        /* update the inversion later */
  3037.         --RedrawingDisabled;
  3038.     }
  3039.     if (checkclearopq(cap->oap))
  3040.         return;
  3041.     }
  3042.  
  3043.     if (ptr == NULL && (n = find_ident_under_cursor(&ptr,
  3044.             (cmdchar == '*' || cmdchar == '#')
  3045.                  ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
  3046.     {
  3047.     clearop(cap->oap);
  3048.     return;
  3049.     }
  3050.  
  3051.     if (cap->count0 && !(cmdchar == 'K' && STRCMP(p_kp, "man") == 0))
  3052.     stuffnumReadbuff(cap->count0);
  3053.     switch (cmdchar)
  3054.     {
  3055.     case '*':
  3056.     case '#':
  3057.         /*
  3058.          * Put cursor at start of word, makes search skip the word
  3059.          * under the cursor.
  3060.          * Call setpcmark() first, so "*``" puts the cursor back where
  3061.          * it was.
  3062.          */
  3063.         setpcmark();
  3064.         curwin->w_cursor.col = ptr - ml_get_curline();
  3065.  
  3066.         if (!g_cmd && vim_iswordc(*ptr))
  3067.         stuffReadbuff((char_u *)"\\<");
  3068.         no_smartcase = TRUE;    /* don't use 'smartcase' now */
  3069.         break;
  3070.  
  3071.     case 'K':
  3072.         if (*p_kp == NUL)
  3073.         stuffReadbuff((char_u *)":he ");
  3074.         else
  3075.         {
  3076.         stuffReadbuff((char_u *)":! ");
  3077.         stuffReadbuff(p_kp);
  3078.         stuffReadbuff((char_u *)" ");
  3079.         if (STRCMP(p_kp, "man") == 0 && cap->count0)
  3080.         {
  3081.             stuffnumReadbuff(cap->count0);
  3082.             stuffReadbuff((char_u *)" ");
  3083.         }
  3084.         }
  3085.         break;
  3086.  
  3087.     case ']':
  3088.         stuffReadbuff((char_u *)":ts ");
  3089.         break;
  3090.  
  3091.     default:
  3092.         if (curbuf->b_help)
  3093.         stuffReadbuff((char_u *)":he ");
  3094.         else if (g_cmd)
  3095.         stuffReadbuff((char_u *)":tj ");
  3096.         else
  3097.         stuffReadbuff((char_u *)":ta ");
  3098.     }
  3099.  
  3100.     /*
  3101.      * Now grab the chars in the identifier
  3102.      */
  3103.     if (cmdchar == '*' || cmdchar == '#')
  3104.     aux_ptr = (char_u *)(p_magic ? ".*~[^$\\" : "^$\\");
  3105.     else
  3106.     aux_ptr = escape_chars;
  3107.     while (n--)
  3108.     {
  3109.     /* put a backslash before \ and some others */
  3110.     if (vim_strchr(aux_ptr, *ptr) != NULL)
  3111.         stuffcharReadbuff('\\');
  3112.     /* don't interpret the characters as edit commands */
  3113.     else if (*ptr < ' ' || *ptr > '~')
  3114.         stuffcharReadbuff(Ctrl('V'));
  3115.     stuffcharReadbuff(*ptr++);
  3116.     }
  3117.  
  3118.     if (       !g_cmd
  3119.         && (cmdchar == '*' || cmdchar == '#')
  3120.         && vim_iswordc(ptr[-1]))
  3121.     stuffReadbuff((char_u *)"\\>");
  3122.     stuffReadbuff((char_u *)"\n");
  3123.  
  3124.     /*
  3125.      * The search commands may be given after an operator.  Therefore they
  3126.      * must be executed right now.
  3127.      */
  3128.     if (cmdchar == '*' || cmdchar == '#')
  3129.     {
  3130.     if (cmdchar == '*')
  3131.         cap->cmdchar = '/';
  3132.     else
  3133.         cap->cmdchar = '?';
  3134.     do_normal_search(cap, searchp, TRUE);
  3135.     }
  3136. }
  3137.  
  3138. /*
  3139.  * Handle scrolling command 'H', 'L' and 'M'.
  3140.  */
  3141.     static void
  3142. do_scroll(cap)
  3143.     CMDARG  *cap;
  3144. {
  3145.     int        used = 0;
  3146.     long    n;
  3147.  
  3148.     cap->oap->motion_type = MLINE;
  3149.     setpcmark();
  3150.  
  3151.     if (cap->cmdchar == 'L')
  3152.     {
  3153.     validate_botline();        /* make sure curwin->w_botline is valid */
  3154.     curwin->w_cursor.lnum = curwin->w_botline - 1;
  3155.     if (cap->count1 - 1 >= curwin->w_cursor.lnum)
  3156.         curwin->w_cursor.lnum = 1;
  3157.     else
  3158.         curwin->w_cursor.lnum -= cap->count1 - 1;
  3159.     }
  3160.     else
  3161.     {
  3162.     if (cap->cmdchar == 'M')
  3163.     {
  3164.         validate_botline();        /* make sure w_empty_rows is valid */
  3165.         for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
  3166.         if ((used += plines(curwin->w_topline + n)) >=
  3167.                 (curwin->w_height - curwin->w_empty_rows + 1) / 2)
  3168.             break;
  3169.         if (n && used > curwin->w_height)
  3170.         --n;
  3171.     }
  3172.     else
  3173.         n = cap->count1 - 1;
  3174.     curwin->w_cursor.lnum = curwin->w_topline + n;
  3175.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3176.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3177.     }
  3178.  
  3179.     cursor_correct();    /* correct for 'so' */
  3180.     beginline(BL_SOL | BL_FIX);
  3181. }
  3182.  
  3183. /*
  3184.  * Cursor right commands.
  3185.  */
  3186.     static void
  3187. do_right(cap)
  3188.     CMDARG    *cap;
  3189. {
  3190.     long    n;
  3191.  
  3192.     cap->oap->motion_type = MCHAR;
  3193.     cap->oap->inclusive = FALSE;
  3194.     for (n = cap->count1; n > 0; --n)
  3195.     {
  3196.     if (oneright() == FAIL)
  3197.     {
  3198.         /*
  3199.          *      <Space> wraps to next line if 'whichwrap' bit 1 set.
  3200.          *          'l' wraps to next line if 'whichwrap' bit 2 set.
  3201.          * CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set
  3202.          */
  3203.         if (       ((cap->cmdchar == ' '
  3204.                 && vim_strchr(p_ww, 's') != NULL)
  3205.             || (cap->cmdchar == 'l'
  3206.                 && vim_strchr(p_ww, 'l') != NULL)
  3207.             || (cap->cmdchar == K_RIGHT
  3208.                 && vim_strchr(p_ww, '>') != NULL))
  3209.             && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  3210.         {
  3211.         /* When deleting we also count the NL as a character.
  3212.          * Set cap->oap->inclusive when last char in the line is
  3213.          * included, move to next line after that */
  3214.         if (       (cap->oap->op_type == OP_DELETE
  3215.                 || cap->oap->op_type == OP_CHANGE)
  3216.             && !cap->oap->inclusive
  3217.             && !lineempty(curwin->w_cursor.lnum))
  3218.             cap->oap->inclusive = TRUE;
  3219.         else
  3220.         {
  3221.             ++curwin->w_cursor.lnum;
  3222.             curwin->w_cursor.col = 0;
  3223.             curwin->w_set_curswant = TRUE;
  3224.             cap->oap->inclusive = FALSE;
  3225.         }
  3226.         continue;
  3227.         }
  3228.         if (cap->oap->op_type == OP_NOP)
  3229.         {
  3230.         /* Only beep and flush if not moved at all */
  3231.         if (n == cap->count1)
  3232.             beep_flush();
  3233.         }
  3234.         else
  3235.         {
  3236.         if (!lineempty(curwin->w_cursor.lnum))
  3237.             cap->oap->inclusive = TRUE;
  3238.         }
  3239.         break;
  3240.     }
  3241.     }
  3242. }
  3243.  
  3244. /*
  3245.  * Cursor left commands.
  3246.  *
  3247.  * Returns TRUE when operator end should not be adjusted.
  3248.  */
  3249.     static int
  3250. do_left(cap)
  3251.     CMDARG    *cap;
  3252. {
  3253.     long    n;
  3254.     int        retval = FALSE;
  3255.  
  3256.     cap->oap->motion_type = MCHAR;
  3257.     cap->oap->inclusive = FALSE;
  3258.     for (n = cap->count1; n > 0; --n)
  3259.     {
  3260.     if (oneleft() == FAIL)
  3261.     {
  3262.         /* <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'.
  3263.          *         'h' wraps to previous line if 'whichwrap' has 'h'.
  3264.          *       CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
  3265.          */
  3266.         if (       (((cap->cmdchar == K_BS
  3267.                 || cap->cmdchar == Ctrl('H'))
  3268.                 && vim_strchr(p_ww, 'b') != NULL)
  3269.             || (cap->cmdchar == 'h'
  3270.                 && vim_strchr(p_ww, 'h') != NULL)
  3271.             || (cap->cmdchar == K_LEFT
  3272.                 && vim_strchr(p_ww, '<') != NULL))
  3273.             && curwin->w_cursor.lnum > 1)
  3274.         {
  3275.         --(curwin->w_cursor.lnum);
  3276.         coladvance(MAXCOL);
  3277.         curwin->w_set_curswant = TRUE;
  3278.  
  3279.         /* When the NL before the first char has to be deleted we
  3280.          * put the cursor on the NUL after the previous line.
  3281.          * This is a very special case, be careful!
  3282.          * don't adjust op_end now, otherwise it won't work */
  3283.         if (       (cap->oap->op_type == OP_DELETE
  3284.                 || cap->oap->op_type == OP_CHANGE)
  3285.             && !lineempty(curwin->w_cursor.lnum))
  3286.         {
  3287.             ++curwin->w_cursor.col;
  3288.             retval = TRUE;
  3289.         }
  3290.         continue;
  3291.         }
  3292.         /* Only beep and flush if not moved at all */
  3293.         else if (cap->oap->op_type == OP_NOP && n == cap->count1)
  3294.         beep_flush();
  3295.         break;
  3296.     }
  3297.     }
  3298.  
  3299.     return retval;
  3300. }
  3301.  
  3302. #ifdef FILE_IN_PATH
  3303. /*
  3304.  * Grab the file name under the cursor and edit it.
  3305.  */
  3306.     static void
  3307. do_gotofile(cap)
  3308.     CMDARG    *cap;
  3309. {
  3310.     char_u    *ptr;
  3311.  
  3312.     ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP, cap->count1);
  3313.     if (ptr != NULL)
  3314.     {
  3315.     /* do autowrite if necessary */
  3316.     if (curbuf_changed() && curbuf->b_nwindows <= 1 && !p_hid)
  3317.         autowrite(curbuf, FALSE);
  3318.     setpcmark();
  3319.     (void)do_ecmd(0, ptr, NULL, NULL, (linenr_t)0, p_hid ? ECMD_HIDE : 0);
  3320.     vim_free(ptr);
  3321.     }
  3322.     else
  3323.     clearop(cap->oap);
  3324. }
  3325. #endif
  3326.  
  3327. /*
  3328.  * Implementation of '?' and '/' commands.
  3329.  */
  3330.     static void
  3331. do_normal_search(cap, searchp, dont_set_mark)
  3332.     CMDARG        *cap;
  3333.     char_u        **searchp;
  3334.     int            dont_set_mark;    /* don't set PC mark */
  3335. {
  3336.     OPARG    *oap = cap->oap;
  3337.     int        i;
  3338.  
  3339.     if ((*searchp = getcmdline(cap->cmdchar, cap->count1, 0)) == NULL)
  3340.     {
  3341.     clearop(oap);
  3342.     return;
  3343.     }
  3344.     oap->motion_type = MCHAR;
  3345.     oap->inclusive = FALSE;
  3346.     curwin->w_set_curswant = TRUE;
  3347.  
  3348.     i = do_search(oap, cap->cmdchar, *searchp, cap->count1,
  3349.         (dont_set_mark ? 0 : SEARCH_MARK) |
  3350.         SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
  3351.     if (i == 0)
  3352.     clearop(oap);
  3353.     else if (i == 2)
  3354.     oap->motion_type = MLINE;
  3355.  
  3356.     /* "/$" will put the cursor after the end of the line, may need to
  3357.      * correct that here */
  3358.     adjust_cursor();
  3359. }
  3360.  
  3361.     static void
  3362. do_csearch(cap, dir, type)
  3363.     CMDARG    *cap;
  3364.     int        dir;
  3365.     int        type;
  3366. {
  3367.     cap->oap->motion_type = MCHAR;
  3368.     if (dir == BACKWARD)
  3369.     cap->oap->inclusive = FALSE;
  3370.     else
  3371.     cap->oap->inclusive = TRUE;
  3372.     curwin->w_set_curswant = TRUE;
  3373.     if (cap->nchar >= 0x100 || !searchc(cap->nchar, dir, type, cap->count1))
  3374.     clearopbeep(cap->oap);
  3375. }
  3376.  
  3377.     static void
  3378. do_brackets(cap, dir)
  3379.     CMDARG    *cap;
  3380.     int        dir;            /* BACKWARD or FORWARD */
  3381. {
  3382.     FPOS    new_pos;
  3383.     FPOS    *pos = NULL;        /* init for GCC */
  3384.     FPOS    old_pos;        /* cursor position before command */
  3385.     int        flag;
  3386.     long    n;
  3387.  
  3388.     cap->oap->motion_type = MCHAR;
  3389.     cap->oap->inclusive = FALSE;
  3390.     old_pos = curwin->w_cursor;
  3391.  
  3392. #ifdef FILE_IN_PATH
  3393.     /*
  3394.      * "[f" or "]f" : Edit file under the cursor (same as "gf")
  3395.      */
  3396.     if (cap->nchar == 'f')
  3397.     do_gotofile(cap);
  3398.     else
  3399. #endif
  3400.  
  3401. #ifdef FIND_IN_PATH
  3402.     /*
  3403.      * Find the occurence(s) of the identifier or define under cursor
  3404.      * in current and included files or jump to the first occurence.
  3405.      *
  3406.      *            search         list        jump
  3407.      *              fwd   bwd    fwd     bwd     fwd    bwd
  3408.      * identifier     "]i"  "[i"   "]I"  "[I"    "]^I"  "[^I"
  3409.      * define          "]d"  "[d"   "]D"  "[D"    "]^D"  "[^D"
  3410.      */
  3411.     if (vim_strchr((char_u *)"iI\011dD\004", cap->nchar) != NULL)
  3412.     {
  3413.     char_u    *ptr;
  3414.     int    len;
  3415.  
  3416.     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
  3417.         clearop(cap->oap);
  3418.     else
  3419.     {
  3420.         find_pattern_in_path(ptr, 0, len, TRUE,
  3421.         cap->count0 == 0 ? !isupper(cap->nchar) : FALSE,
  3422.         ((cap->nchar & 0xf) == ('d' & 0xf)) ?  FIND_DEFINE : FIND_ANY,
  3423.         cap->count1,
  3424.         isupper(cap->nchar) ? ACTION_SHOW_ALL :
  3425.                 islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO,
  3426.         cap->cmdchar == ']' ? curwin->w_cursor.lnum : (linenr_t)1,
  3427.         (linenr_t)MAXLNUM);
  3428.         curwin->w_set_curswant = TRUE;
  3429.     }
  3430.     }
  3431.     else
  3432. #endif
  3433.  
  3434.     /*
  3435.      * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
  3436.      * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
  3437.      * "[/", "[*", "]/", "]*": go to Nth comment start/end.
  3438.      */
  3439.     if (  (cap->cmdchar == '['
  3440.         && vim_strchr((char_u *)"{(*/#", cap->nchar) != NULL)
  3441.         || (cap->cmdchar == ']'
  3442.         && vim_strchr((char_u *)"})*/#", cap->nchar) != NULL))
  3443.     {
  3444.     if (cap->nchar == '*')
  3445.         cap->nchar = '/';
  3446.     new_pos.lnum = 0;
  3447.     for (n = cap->count1; n > 0; --n)
  3448.     {
  3449.         if ((pos = findmatchlimit(cap->oap, cap->nchar,
  3450.         (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
  3451.         {
  3452.         if (new_pos.lnum == 0)    /* nothing found */
  3453.             clearopbeep(cap->oap);
  3454.         else
  3455.             pos = &new_pos;    /* use last one found */
  3456.         break;
  3457.         }
  3458.         curwin->w_cursor = *pos;
  3459.         new_pos = *pos;
  3460.     }
  3461.     curwin->w_cursor = old_pos;
  3462.     if (pos != NULL)
  3463.     {
  3464.         setpcmark();
  3465.         curwin->w_cursor = *pos;
  3466.         curwin->w_set_curswant = TRUE;
  3467.     }
  3468.     }
  3469.  
  3470.     /*
  3471.      * "[[", "[]", "]]" and "][": move to start or end of function
  3472.      */
  3473.     else if (cap->nchar == '[' || cap->nchar == ']')
  3474.     {
  3475.     if (cap->nchar == cap->cmdchar)            /* "]]" or "[[" */
  3476.         flag = '{';
  3477.     else
  3478.         flag = '}';            /* "][" or "[]" */
  3479.  
  3480.     curwin->w_set_curswant = TRUE;
  3481.     /*
  3482.      * Imitate strange Vi behaviour: When using "]]" with an operator
  3483.      * we also stop at '}'.
  3484.      */
  3485.     if (!findpar(cap->oap, dir, cap->count1, flag,
  3486.           (cap->oap->op_type != OP_NOP && dir == FORWARD && flag == '{')))
  3487.         clearopbeep(cap->oap);
  3488.     else if (cap->oap->op_type == OP_NOP)
  3489.         beginline(BL_WHITE | BL_FIX);
  3490.     }
  3491.  
  3492.     /*
  3493.      * "[p", "[P", "]P" and "]p": put with indent adjustment
  3494.      */
  3495.     else if (cap->nchar == 'p' || cap->nchar == 'P')
  3496.     {
  3497.     if (!checkclearopq(cap->oap))
  3498.     {
  3499.         prep_redo_cmd(cap);
  3500.         do_put(cap->oap->regname,
  3501.           (cap->cmdchar == ']' && cap->nchar == 'p') ? FORWARD : BACKWARD,
  3502.                                cap->count1, TRUE);
  3503.     }
  3504.     }
  3505.  
  3506. #ifdef USE_MOUSE
  3507.     /*
  3508.      * [ or ] followed by a middle mouse click: put selected text with
  3509.      * indent adjustment.  Any other button just does as usual.
  3510.      */
  3511.     else if (cap->nchar >= K_LEFTMOUSE && cap->nchar <= K_RIGHTRELEASE)
  3512.     {
  3513.     (void)do_mouse(cap->oap, cap->nchar,
  3514.            (cap->cmdchar == ']') ? FORWARD : BACKWARD, cap->count1, TRUE);
  3515.     }
  3516. #endif /* USE_MOUSE */
  3517.  
  3518.     /* Not a valid cap->nchar. */
  3519.     else
  3520.     clearopbeep(cap->oap);
  3521. }
  3522.  
  3523. /*
  3524.  * Handle Normal mode "%" command.
  3525.  */
  3526.     static void
  3527. do_percent(cap)
  3528.     CMDARG    *cap;
  3529. {
  3530.     FPOS    *pos;
  3531.  
  3532.     cap->oap->inclusive = TRUE;
  3533.     if (cap->count0)        /* {cnt}% : goto {cnt} percentage in file */
  3534.     {
  3535.     if (cap->count0 > 100)
  3536.         clearopbeep(cap->oap);
  3537.     else
  3538.     {
  3539.         cap->oap->motion_type = MLINE;
  3540.         setpcmark();
  3541.                 /* round up, so CTRL-G will give same value */
  3542.         curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
  3543.                               cap->count0 + 99) / 100;
  3544.         beginline(BL_SOL | BL_FIX);
  3545.     }
  3546.     }
  3547.     else            /* "%" : go to matching paren */
  3548.     {
  3549.     cap->oap->motion_type = MCHAR;
  3550.     if ((pos = findmatch(cap->oap, NUL)) == NULL)
  3551.         clearopbeep(cap->oap);
  3552.     else
  3553.     {
  3554.         setpcmark();
  3555.         curwin->w_cursor = *pos;
  3556.         curwin->w_set_curswant = TRUE;
  3557.     }
  3558.     }
  3559. }
  3560.  
  3561. /*
  3562.  * Handle the "r" command.
  3563.  */
  3564.     static int
  3565. do_replace(cap)
  3566.     CMDARG    *cap;
  3567. {
  3568.     char_u    *ptr;
  3569.     int        had_ctrl_v;
  3570.     int        command_busy = FALSE;
  3571.     long    n;
  3572.  
  3573.     ptr = ml_get_cursor();
  3574.     /* special key or not enough characters to replace */
  3575.     if (cap->nchar >= 0x100 || STRLEN(ptr) < (unsigned)cap->count1)
  3576.     {
  3577.     clearopbeep(cap->oap);
  3578.     return FALSE;
  3579.     }
  3580.  
  3581.     /*
  3582.      * Replacing with a TAB is done by edit(), because it is complicated when
  3583.      * 'expandtab', 'smarttab' or 'softtabstop' is set.
  3584.      * Other characters are done below to avoid problems with things like
  3585.      * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  3586.      */
  3587.     if (cap->nchar == '\t' && (curbuf->b_p_et || p_sta))
  3588.     {
  3589.     stuffnumReadbuff(cap->count1);
  3590.     stuffcharReadbuff('R');
  3591.     stuffcharReadbuff('\t');
  3592.     stuffcharReadbuff(ESC);
  3593.     return FALSE;
  3594.     }
  3595.  
  3596.     if (cap->nchar == Ctrl('V'))        /* get another character */
  3597.     {
  3598.     had_ctrl_v = Ctrl('V');
  3599.     cap->nchar = get_literal();
  3600.     }
  3601.     else
  3602.     had_ctrl_v = NUL;
  3603.     if (u_save_cursor() == FAIL)    /* save line for undo */
  3604.     return FALSE;
  3605.  
  3606.     if (had_ctrl_v != Ctrl('V') && (cap->nchar == '\r' || cap->nchar == '\n'))
  3607.     {
  3608.     /*
  3609.      * Replace character(s) by a single newline.
  3610.      * Strange vi behaviour: Only one newline is inserted.
  3611.      * Delete the characters here.
  3612.      * Insert the newline with an insert command, takes care of
  3613.      * autoindent.    The insert command depends on being on the last
  3614.      * character of a line or not.
  3615.      */
  3616.     (void)del_chars(cap->count1, FALSE);    /* delete the characters */
  3617.     stuffcharReadbuff('\r');
  3618.     stuffcharReadbuff(ESC);
  3619.     /*
  3620.      * Give 'r' to edit(), to get the redo command right.
  3621.      */
  3622.     command_busy = edit('r', FALSE, cap->count1);
  3623.     }
  3624.     else
  3625.     {
  3626.     prep_redo(cap->oap->regname, cap->count1,
  3627.                         NUL, 'r', had_ctrl_v, cap->nchar);
  3628.     for (n = cap->count1; n > 0; --n)    /* replace the characters */
  3629.     {
  3630.         /*
  3631.          * Replace a 'normal' character.
  3632.          * Get ptr again, because u_save and/or showmatch() will have
  3633.          * released the line.  At the same time we let know that the line
  3634.          * will be changed.
  3635.          */
  3636.         ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
  3637.         ptr[curwin->w_cursor.col] = cap->nchar;
  3638.         if (       p_sm
  3639.             && (cap->nchar == ')'
  3640.             || cap->nchar == '}'
  3641.             || cap->nchar == ']'))
  3642.         showmatch();
  3643.         ++curwin->w_cursor.col;
  3644.     }
  3645.     --curwin->w_cursor.col;        /* cursor on the last replaced char */
  3646.     curwin->w_set_curswant = TRUE;
  3647.     set_last_insert(cap->nchar);
  3648.     changed_cline_bef_curs();   /* update cursor screen pos. later */
  3649.     /* w_botline might change a bit when replacing special characters */
  3650.     approximate_botline();
  3651.     update_screenline();
  3652.     }
  3653.     CHANGED;
  3654.  
  3655.     return command_busy;
  3656. }
  3657.  
  3658. /*
  3659.  * 'o': Exchange start and end of Visual area.
  3660.  * 'O': same, but in block mode exchange left and right corners.
  3661.  */
  3662.     static void
  3663. switch_visual(cap)
  3664.     CMDARG    *cap;
  3665. {
  3666.     FPOS    old_cursor;
  3667.     colnr_t    left, right;
  3668.  
  3669.     if ((cap->cmdchar == 'O') && VIsual_mode == Ctrl('V'))
  3670.     {
  3671.     old_cursor = curwin->w_cursor;
  3672.     getvcols(&old_cursor, &VIsual, &left, &right);
  3673.     curwin->w_cursor.lnum = VIsual.lnum;
  3674.     coladvance(left);
  3675.     VIsual = curwin->w_cursor;
  3676.     curwin->w_cursor.lnum = old_cursor.lnum;
  3677.     coladvance(right);
  3678.     curwin->w_curswant = right;
  3679.     if (curwin->w_cursor.col == old_cursor.col)
  3680.     {
  3681.         curwin->w_cursor.lnum = VIsual.lnum;
  3682.         coladvance(right);
  3683.         VIsual = curwin->w_cursor;
  3684.         curwin->w_cursor.lnum = old_cursor.lnum;
  3685.         coladvance(left);
  3686.         curwin->w_curswant = left;
  3687.     }
  3688.     }
  3689.     if (cap->cmdchar != 'O' || VIsual_mode != Ctrl('V'))
  3690.     {
  3691.     old_cursor = curwin->w_cursor;
  3692.     curwin->w_cursor = VIsual;
  3693.     VIsual = old_cursor;
  3694.     curwin->w_set_curswant = TRUE;
  3695.     }
  3696. }
  3697.  
  3698. /*
  3699.  * Swap case for "~" command, when it does not work like an operator.
  3700.  */
  3701.     static void
  3702. do_swapchar(cap)
  3703.     CMDARG    *cap;
  3704. {
  3705.     long    n;
  3706.  
  3707.     if (checkclearopq(cap->oap))
  3708.     return;
  3709.  
  3710.     if (lineempty(curwin->w_cursor.lnum))
  3711.     {
  3712.     clearopbeep(cap->oap);
  3713.     return;
  3714.     }
  3715.  
  3716.     prep_redo_cmd(cap);
  3717.  
  3718.     if (u_save_cursor() == FAIL)
  3719.     return;
  3720.  
  3721.     for (n = cap->count1; n > 0; --n)
  3722.     {
  3723.     if (gchar_cursor() == NUL)
  3724.         break;
  3725.     swapchar(cap->oap->op_type, &curwin->w_cursor);
  3726.     inc_cursor();
  3727.     }
  3728.  
  3729.     adjust_cursor();
  3730.     curwin->w_set_curswant = TRUE;
  3731.     CHANGED;
  3732.  
  3733.     /* assume that the length of the line doesn't change, so w_botline
  3734.      * remains valid */
  3735.     update_screenline();
  3736. }
  3737.  
  3738. /*
  3739.  * Move cursor to mark.
  3740.  */
  3741.     static void
  3742. do_cursormark(cap, flag, pos)
  3743.     CMDARG    *cap;
  3744.     int        flag;
  3745.     FPOS    *pos;
  3746. {
  3747.     if (check_mark(pos) == FAIL)
  3748.     clearop(cap->oap);
  3749.     else
  3750.     {
  3751.     if (cap->cmdchar == '\'' || cap->cmdchar == '`')
  3752.         setpcmark();
  3753.     curwin->w_cursor = *pos;
  3754.     if (flag)
  3755.         beginline(BL_WHITE | BL_FIX);
  3756.     else
  3757.         adjust_cursor();
  3758.     }
  3759.     cap->oap->motion_type = flag ? MLINE : MCHAR;
  3760.     cap->oap->inclusive = FALSE;        /* ignored if not MCHAR */
  3761.     curwin->w_set_curswant = TRUE;
  3762. }
  3763.  
  3764. /*
  3765.  * Handle commands that are operators in Visual mode.
  3766.  */
  3767.     static void
  3768. do_visop(cap)
  3769.     CMDARG    *cap;
  3770. {
  3771.     static char_u trans[] = "YyDdCcxdXd";
  3772.  
  3773.     /* Uppercase means linewise, except in block mode, then "D" deletes till
  3774.      * the end of the line. */
  3775.     if (isupper(cap->cmdchar))
  3776.     {
  3777.     if (VIsual_mode != Ctrl('V'))
  3778.         VIsual_mode = 'V';
  3779.     else if (cap->cmdchar == 'D')
  3780.         curwin->w_curswant = MAXCOL;
  3781.     }
  3782.     cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1);
  3783.     do_operator(cap);
  3784. }
  3785.  
  3786. /*
  3787.  * Translate a command into another command.
  3788.  */
  3789.     static void
  3790. do_optrans(cap)
  3791.     CMDARG    *cap;
  3792. {
  3793.     static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
  3794.                   (char_u *)"d$", (char_u *)"c$",
  3795.                   (char_u *)"cl", (char_u *)"cc",
  3796.                   (char_u *)"yy", (char_u *)":s\r"};
  3797.     static char_u *str = (char_u *)"xXDCsSY&";
  3798.  
  3799.     if (!checkclearopq(cap->oap))
  3800.     {
  3801.     if (cap->count0)
  3802.         stuffnumReadbuff(cap->count0);
  3803.     stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
  3804.     }
  3805. }
  3806.  
  3807. /*
  3808.  * Handle "'" and "`" commands.
  3809.  */
  3810.     static void
  3811. do_gomark(cap, flag)
  3812.     CMDARG    *cap;
  3813.     int        flag;
  3814. {
  3815.     FPOS    *pos;
  3816.  
  3817.     pos = getmark(cap->nchar, (cap->oap->op_type == OP_NOP));
  3818.     if (pos == (FPOS *)-1)        /* jumped to other file */
  3819.     {
  3820.     if (flag)
  3821.         beginline(BL_WHITE | BL_FIX);
  3822.     else
  3823.         adjust_cursor();
  3824.     }
  3825.     else
  3826.     do_cursormark(cap, flag, pos);
  3827. }
  3828.  
  3829. /*
  3830.  * Handle CTRL-O and CTRL-I commands.
  3831.  */
  3832.     static void
  3833. do_pcmark(cap)
  3834.     CMDARG    *cap;
  3835. {
  3836.     FPOS    *pos;
  3837.  
  3838.     if (!checkclearopq(cap->oap))
  3839.     {
  3840.     pos = movemark((int)cap->count1);
  3841.     if (pos == (FPOS *)-1)        /* jump to other file */
  3842.     {
  3843.         curwin->w_set_curswant = TRUE;
  3844.         adjust_cursor();
  3845.     }
  3846.     else if (pos != NULL)            /* can jump */
  3847.         do_cursormark(cap, FALSE, pos);
  3848.     else
  3849.         clearopbeep(cap->oap);
  3850.     }
  3851. }
  3852.  
  3853. /*
  3854.  * Handle '"' command.
  3855.  */
  3856.     static void
  3857. do_regname(cap, opnump)
  3858.     CMDARG    *cap;
  3859.     linenr_t    *opnump;
  3860. {
  3861.     if (checkclearop(cap->oap))
  3862.     return;
  3863. #ifdef WANT_EVAL
  3864.     if (cap->nchar == '=')
  3865.     cap->nchar = get_expr_register();
  3866. #endif
  3867.     if (cap->nchar != NUL && valid_yank_reg(cap->nchar, FALSE))
  3868.     {
  3869.     cap->oap->regname = cap->nchar;
  3870.     *opnump = cap->count0;        /* remember count before '"' */
  3871.     }
  3872.     else
  3873.     clearopbeep(cap->oap);
  3874. }
  3875.  
  3876. /*
  3877.  * Handle "v", "V" and "CTRL-V" commands.
  3878.  */
  3879.     static void
  3880. do_visual(cap)
  3881.     CMDARG  *cap;
  3882. {
  3883.     if (VIsual_active)        /* change Visual mode */
  3884.     {
  3885.     if (VIsual_mode == cap->cmdchar)    /* stop visual mode */
  3886.         end_visual_mode();
  3887.     else                    /* toggle char/block mode */
  3888.     {                    /*       or char/line mode */
  3889.         VIsual_mode = cap->cmdchar;
  3890.         showmode();
  3891.     }
  3892.     update_curbuf(NOT_VALID);        /* update the inversion */
  3893.     }
  3894.     else            /* start Visual mode */
  3895.     {
  3896.     check_visual_highlight();
  3897.     if (cap->count0)            /* use previously selected part */
  3898.     {
  3899.         if (resel_VIsual_mode == NUL)   /* there is none */
  3900.         {
  3901.         beep_flush();
  3902.         return;
  3903.         }
  3904.         VIsual = curwin->w_cursor;
  3905.         VIsual_active = TRUE;
  3906. #ifdef USE_MOUSE
  3907.         setmouse();
  3908. #endif
  3909.         if (p_smd)
  3910.         redraw_cmdline = TRUE;        /* show visual mode later */
  3911.         /*
  3912.          * For V and ^V, we multiply the number of lines even if there
  3913.          * was only one -- webb
  3914.          */
  3915.         if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
  3916.         {
  3917.         curwin->w_cursor.lnum +=
  3918.                     resel_VIsual_line_count * cap->count0 - 1;
  3919.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3920.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3921.         }
  3922.         VIsual_mode = resel_VIsual_mode;
  3923.         if (VIsual_mode == 'v')
  3924.         {
  3925.         if (resel_VIsual_line_count <= 1)
  3926.             curwin->w_cursor.col += resel_VIsual_col * cap->count0 - 1;
  3927.         else
  3928.             curwin->w_cursor.col = resel_VIsual_col;
  3929.         }
  3930.         if (resel_VIsual_col == MAXCOL)
  3931.         {
  3932.         curwin->w_curswant = MAXCOL;
  3933.         coladvance(MAXCOL);
  3934.         }
  3935.         else if (VIsual_mode == Ctrl('V'))
  3936.         {
  3937.         validate_virtcol();
  3938.         curwin->w_curswant = curwin->w_virtcol +
  3939.                        resel_VIsual_col * cap->count0 - 1;
  3940.         coladvance(curwin->w_curswant);
  3941.         }
  3942.         else
  3943.         curwin->w_set_curswant = TRUE;
  3944.         update_curbuf(NOT_VALID);    /* show the inversion */
  3945.     }
  3946.     else
  3947.     {
  3948.         VIsual = curwin->w_cursor;
  3949.         VIsual_mode = cap->cmdchar;
  3950.         VIsual_active = TRUE;
  3951. #ifdef USE_MOUSE
  3952.         setmouse();
  3953. #endif
  3954.         if (p_smd)
  3955.         redraw_cmdline = TRUE;    /* show visual mode later */
  3956.         update_screenline();    /* start the inversion */
  3957.     }
  3958.     }
  3959. }
  3960.  
  3961. /*
  3962.  * Handle the "g" command.
  3963.  */
  3964.     static int
  3965. do_g_cmd(cap, searchp)
  3966.     CMDARG    *cap;
  3967.     char_u    **searchp;
  3968. {
  3969.     OPARG    *oap = cap->oap;
  3970.     FPOS    tpos;
  3971.     int        i;
  3972.     int        flag = FALSE;
  3973.     int        command_busy = FALSE;
  3974.  
  3975.     switch (cap->nchar)
  3976.     {
  3977.     /*
  3978.      * "gv": Reselect the previous Visual area.  If Visual already active,
  3979.      *         exchange previous and current Visual area.
  3980.      */
  3981.     case 'v':
  3982.     if (checkclearop(oap))
  3983.         break;
  3984.  
  3985.     if (       curbuf->b_visual_start.lnum == 0
  3986.         || curbuf->b_visual_start.lnum > curbuf->b_ml.ml_line_count
  3987.         || curbuf->b_visual_end.lnum == 0)
  3988.         beep_flush();
  3989.     else
  3990.     {
  3991.         if (VIsual_active)
  3992.         {
  3993.         tpos = VIsual;
  3994.         VIsual = curbuf->b_visual_start;
  3995.         curbuf->b_visual_start = tpos;
  3996.         i = VIsual_mode;
  3997.         VIsual_mode = curbuf->b_visual_mode;
  3998.         curbuf->b_visual_mode = i;
  3999.         tpos = curwin->w_cursor;
  4000.         curwin->w_cursor = curbuf->b_visual_end;
  4001.         curbuf->b_visual_end = tpos;
  4002.         }
  4003.         else
  4004.         {
  4005.         VIsual = curbuf->b_visual_start;
  4006.         curwin->w_cursor = curbuf->b_visual_end;
  4007.         VIsual_mode = curbuf->b_visual_mode;
  4008.         }
  4009.  
  4010.         check_cursor_lnum();
  4011.         update_topline();
  4012.         VIsual_active = TRUE;
  4013. #ifdef USE_MOUSE
  4014.         setmouse();
  4015. #endif
  4016.         update_curbuf(NOT_VALID);
  4017.         showmode();
  4018.     }
  4019.     break;
  4020.  
  4021.     /*
  4022.      * "gj" and "gk" two new funny movement keys -- up and down
  4023.      * movement based on *screen* line rather than *file* line.
  4024.      */
  4025.     case 'j':
  4026.     case K_DOWN:
  4027.     /* with 'nowrap' it works just like the normal "j" command */
  4028.     if (!curwin->w_p_wrap)
  4029.     {
  4030.         oap->motion_type = MLINE;
  4031.         i = cursor_down(cap->count1, oap->op_type == OP_NOP);
  4032.     }
  4033.     else
  4034.         i = screengo(oap, FORWARD, cap->count1);
  4035.     if (i == FAIL)
  4036.         clearopbeep(oap);
  4037.     break;
  4038.  
  4039.     case 'k':
  4040.     case K_UP:
  4041.     /* with 'nowrap' it works just like the normal "k" command */
  4042.     if (!curwin->w_p_wrap)
  4043.     {
  4044.         oap->motion_type = MLINE;
  4045.         i = cursor_up(cap->count1, oap->op_type == OP_NOP);
  4046.     }
  4047.     else
  4048.         i = screengo(oap, BACKWARD, cap->count1);
  4049.     if (i == FAIL)
  4050.         clearopbeep(oap);
  4051.     break;
  4052.  
  4053.     /*
  4054.      * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
  4055.      */
  4056.     case '^':
  4057.     flag = TRUE;
  4058.     /* FALLTHROUGH */
  4059.  
  4060.     case '0':
  4061.     case K_HOME:
  4062.     case K_KHOME:
  4063.     oap->motion_type = MCHAR;
  4064.     oap->inclusive = FALSE;
  4065.     if (curwin->w_p_wrap)
  4066.     {
  4067.         validate_virtcol();
  4068.         i = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  4069.                                Columns) * Columns;
  4070.         if (curwin->w_p_nu && i > 8)
  4071.         i -= 8;
  4072.     }
  4073.     else
  4074.         i = curwin->w_leftcol;
  4075.     coladvance((colnr_t)i);
  4076.     if (flag)
  4077.     {
  4078.         do
  4079.         i = gchar_cursor();
  4080.         while (vim_iswhite(i) && oneright() == OK);
  4081.     }
  4082.     curwin->w_set_curswant = TRUE;
  4083.     break;
  4084.  
  4085.     case '$':
  4086.     case K_END:
  4087.     case K_KEND:
  4088.     oap->motion_type = MCHAR;
  4089.     oap->inclusive = TRUE;
  4090.     if (curwin->w_p_wrap)
  4091.     {
  4092.         curwin->w_curswant = MAXCOL;    /* so we stay at the end */
  4093.         if (cap->count1 == 1)
  4094.         {
  4095.         validate_virtcol();
  4096.         i = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  4097.                            Columns + 1) * Columns - 1;
  4098.         if (curwin->w_p_nu && i > 8)
  4099.             i -= 8;
  4100.         coladvance((colnr_t)i);
  4101.         }
  4102.         else if (screengo(oap, FORWARD, cap->count1 - 1) == FAIL)
  4103.         clearopbeep(oap);
  4104.     }
  4105.     else
  4106.     {
  4107.         i = curwin->w_leftcol + Columns - 1;
  4108.         if (curwin->w_p_nu)
  4109.         i -= 8;
  4110.         coladvance((colnr_t)i);
  4111.         curwin->w_set_curswant = TRUE;
  4112.     }
  4113.     break;
  4114.  
  4115.     /*
  4116.      * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
  4117.      */
  4118.     case '*':
  4119.     case '#':
  4120.     do_ident(cap, searchp);
  4121.     break;
  4122.  
  4123.     /*
  4124.      * ge and gE: go back to end of word
  4125.      */
  4126.     case 'e':
  4127.     case 'E':
  4128.     oap->motion_type = MCHAR;
  4129.     curwin->w_set_curswant = TRUE;
  4130.     oap->inclusive = TRUE;
  4131.     if (bckend_word(cap->count1, cap->nchar == 'E', FALSE) == FAIL)
  4132.         clearopbeep(oap);
  4133.     break;
  4134.  
  4135.     /*
  4136.      * "g CTRL-G": display info about cursor position
  4137.      */
  4138.     case Ctrl('G'):
  4139.     cursor_pos_info();
  4140.     break;
  4141.  
  4142.     /*
  4143.      * "gI": Start insert in column 1.
  4144.      */
  4145.     case 'I':
  4146.     beginline(0);
  4147.     if (!checkclearopq(oap))
  4148.     {
  4149.         if (u_save_cursor() == OK)
  4150.         command_busy = edit('g', FALSE, cap->count1);
  4151.     }
  4152.     break;
  4153.  
  4154. #ifdef FILE_IN_PATH
  4155.     /*
  4156.      * "gf": goto file, edit file under cursor
  4157.      * "]f" and "[f": can also be used.
  4158.      */
  4159.     case 'f':
  4160.     do_gotofile(cap);
  4161.     break;
  4162. #endif
  4163.  
  4164.     /*
  4165.      * "gs": Goto sleep, but keep on checking for CTRL-C
  4166.      */
  4167.     case 's':
  4168.     while (cap->count1-- && !got_int)
  4169.     {
  4170.         ui_delay(1000L, TRUE);
  4171.         ui_breakcheck();
  4172.     }
  4173.     break;
  4174.  
  4175.     /*
  4176.      * "ga": Display the ascii value of the character under the
  4177.      * cursor.    It is displayed in decimal, hex, and octal. -- webb
  4178.      */
  4179.     case 'a':
  4180.     do_ascii();
  4181.     break;
  4182.  
  4183.     /*
  4184.      * "gg": Goto the first line in file.  With a count it goes to
  4185.      * that line number like for "G". -- webb
  4186.      */
  4187.     case 'g':
  4188.     do_goto(oap, cap->count0);    /* do_goto() will change 0 into 1 */
  4189.     break;
  4190.  
  4191.     /*
  4192.      *     Two-character operators:
  4193.      *     "gq"        Format text
  4194.      *     "g~"        Toggle the case of the text.
  4195.      *     "gu"        Change text to lower case.
  4196.      *     "gU"        Change text to upper case.
  4197.      */
  4198.     case 'q':
  4199.     case '~':
  4200.     case 'u':
  4201.     case 'U':
  4202.     oap->op_prechar = 'g';
  4203.     cap->cmdchar = cap->nchar;
  4204.     do_operator(cap);
  4205.     break;
  4206.  
  4207. /*
  4208.  * "gd": Find first occurence of pattern under the cursor in the
  4209.  *     current function
  4210.  * "gD": idem, but in the current file.
  4211.  */
  4212.     case 'd':
  4213.     case 'D':
  4214.     do_gd(oap, cap->nchar);
  4215.     break;
  4216.  
  4217. #ifdef USE_MOUSE
  4218.     /*
  4219.      * g<*Mouse> : <C-*mouse>
  4220.      */
  4221.     case K_MIDDLEMOUSE:
  4222.     case K_MIDDLEDRAG:
  4223.     case K_MIDDLERELEASE:
  4224.     case K_LEFTMOUSE:
  4225.     case K_LEFTDRAG:
  4226.     case K_LEFTRELEASE:
  4227.     case K_RIGHTMOUSE:
  4228.     case K_RIGHTDRAG:
  4229.     case K_RIGHTRELEASE:
  4230.     mod_mask = MOD_MASK_CTRL;
  4231.     (void)do_mouse(oap, cap->nchar, BACKWARD, cap->count1, FALSE);
  4232.     break;
  4233.  
  4234.     case K_IGNORE:
  4235.     break;
  4236. #endif
  4237.  
  4238.     case Ctrl(']'):        /* :tag or :tselect for current identifier */
  4239.     case ']':            /* :tselect for current identifier */
  4240.     do_ident(cap, searchp);
  4241.     break;
  4242.  
  4243.     default:
  4244.     clearopbeep(oap);
  4245.     break;
  4246.     }
  4247.  
  4248.     return command_busy;
  4249. }
  4250.  
  4251. /*
  4252.  * Handle "o" and "O" commands.
  4253.  */
  4254.     static int
  4255. do_opencmd(cap)
  4256.     CMDARG    *cap;
  4257. {
  4258.     int        command_busy = FALSE;
  4259.  
  4260.     if (!checkclearopq(cap->oap))
  4261.     {
  4262.     if (has_format_option(FO_OPEN_COMS))
  4263.         fo_do_comments = TRUE;
  4264.     if (u_save((linenr_t)(curwin->w_cursor.lnum -
  4265.                            (cap->cmdchar == 'O' ? 1 : 0)),
  4266.            (linenr_t)(curwin->w_cursor.lnum +
  4267.                            (cap->cmdchar == 'o' ? 1 : 0))
  4268.                ) == OK
  4269.         && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
  4270.                               TRUE, FALSE, 0))
  4271.         command_busy = edit(cap->cmdchar, TRUE, cap->count1);
  4272.     fo_do_comments = FALSE;
  4273.     }
  4274.     return command_busy;
  4275. }
  4276.  
  4277. /*
  4278.  * Handle an operator command.
  4279.  */
  4280.     static void
  4281. do_operator(cap)
  4282.     CMDARG    *cap;
  4283. {
  4284.     int        i;
  4285.  
  4286.     i = vim_strchr(op_chars, cap->cmdchar) - op_chars + 1;
  4287.     if (i == cap->oap->op_type)        /* double operator works on lines */
  4288.     do_lineop(cap);
  4289.     else if (!checkclearop(cap->oap))
  4290.     {
  4291.     cap->oap->start = curwin->w_cursor;
  4292.     cap->oap->op_type = i;
  4293.     }
  4294. }
  4295.  
  4296. /*
  4297.  * Handle linewise operator "dd", "yy", etc.
  4298.  */
  4299.     static void
  4300. do_lineop(cap)
  4301.     CMDARG    *cap;
  4302. {
  4303.     cap->oap->motion_type = MLINE;
  4304.     if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL)
  4305.     clearopbeep(cap->oap);
  4306.     else if (  cap->oap->op_type == OP_DELETE
  4307.         || cap->oap->op_type == OP_LSHIFT
  4308.         || cap->oap->op_type == OP_RSHIFT)
  4309.     beginline(BL_SOL | BL_FIX);
  4310.     else if (cap->oap->op_type != OP_YANK)    /* 'Y' does not move cursor */
  4311.     beginline(BL_WHITE | BL_FIX);
  4312. }
  4313.  
  4314. /*
  4315.  * Handle back-word command "b".
  4316.  */
  4317.     static void
  4318. do_bck_word(cap, type)
  4319.     CMDARG    *cap;
  4320.     int        type;
  4321. {
  4322.     cap->oap->motion_type = MCHAR;
  4323.     cap->oap->inclusive = FALSE;
  4324.     curwin->w_set_curswant = TRUE;
  4325.     if (bck_word(cap->count1, type, FALSE) == FAIL)
  4326.     clearopbeep(cap->oap);
  4327. }
  4328.  
  4329. /*
  4330.  * Handle word motion commands "e", "E", "w" and "W".
  4331.  */
  4332.     static void
  4333. do_wordcmd(cap, type)
  4334.     CMDARG    *cap;
  4335.     int        type;
  4336. {
  4337.     int        n;
  4338.     int        word_end;
  4339.     int        flag = FALSE;
  4340.  
  4341.     /*
  4342.      * Inclusive has been set for the "E" and "e" command.
  4343.      */
  4344.     word_end = cap->oap->inclusive;
  4345.  
  4346.     /*
  4347.      * "cw" and "cW" are a special case.
  4348.      */
  4349.     if (!word_end && cap->oap->op_type == OP_CHANGE)
  4350.     {
  4351.     n = gchar_cursor();
  4352.     if (n != NUL)            /* not an empty line */
  4353.     {
  4354.         if (vim_iswhite(n))
  4355.         {
  4356.         /*
  4357.          * Reproduce a funny Vi behaviour: "cw" on a blank only
  4358.          * changes one character, not all blanks until the start of
  4359.          * the next word.  Only do this when the 'w' flag is included
  4360.          * in 'cpoptions'.
  4361.          */
  4362.         if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
  4363.         {
  4364.             cap->oap->inclusive = TRUE;
  4365.             cap->oap->motion_type = MCHAR;
  4366.             return;
  4367.         }
  4368.         }
  4369.         else
  4370.         {
  4371.         /*
  4372.          * This is a little strange. To match what the real Vi does,
  4373.          * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
  4374.          * that we are not on a space or a TAB.  This seems impolite
  4375.          * at first, but it's really more what we mean when we say
  4376.          * 'cw'.
  4377.          * Another strangeness: When standing on the end of a word
  4378.          * "ce" will change until the end of the next wordt, but "cw"
  4379.          * will change only one character! This is done by setting
  4380.          * flag.
  4381.          */
  4382.         cap->oap->inclusive = TRUE;
  4383.         word_end = TRUE;
  4384.         flag = TRUE;
  4385.         }
  4386.     }
  4387.     }
  4388.  
  4389.     cap->oap->motion_type = MCHAR;
  4390.     curwin->w_set_curswant = TRUE;
  4391.     if (word_end)
  4392.     n = end_word(cap->count1, type, flag, FALSE);
  4393.     else
  4394.     n = fwd_word(cap->count1, type, cap->oap->op_type != OP_NOP);
  4395.     if (n == FAIL && cap->oap->op_type == OP_NOP)
  4396.     clearopbeep(cap->oap);
  4397.  
  4398.     /* Don't leave the cursor on the NUL past a line */
  4399.     if (curwin->w_cursor.col && gchar_cursor() == NUL)
  4400.     {
  4401.     --curwin->w_cursor.col;
  4402.     cap->oap->inclusive = TRUE;
  4403.     }
  4404. }
  4405.  
  4406.     static void
  4407. do_goto(oap, lnum)
  4408.     OPARG   *oap;
  4409.     long    lnum;
  4410. {
  4411.     oap->motion_type = MLINE;
  4412.     setpcmark();
  4413.     if (lnum < 1L)
  4414.     lnum = 1L;
  4415.     else if (lnum > curbuf->b_ml.ml_line_count)
  4416.     lnum = curbuf->b_ml.ml_line_count;
  4417.     curwin->w_cursor.lnum = lnum;
  4418.     beginline(BL_SOL | BL_FIX);
  4419. }
  4420.  
  4421. /*
  4422.  * ESC in Normal mode: beep, but don't flush buffers.
  4423.  * Don't even beep if we are canceling a command.
  4424.  */
  4425.     static void
  4426. do_esc(cap, opnum)
  4427.     CMDARG    *cap;
  4428.     linenr_t    opnum;
  4429. {
  4430.     if (VIsual_active)
  4431.     {
  4432.     end_visual_mode();        /* stop Visual */
  4433.     /* leave cursor on first line/col */
  4434.     if (lt(VIsual, curwin->w_cursor))
  4435.         curwin->w_cursor = VIsual;
  4436.     update_curbuf(NOT_VALID);
  4437.     }
  4438.     else if (cap->oap->op_type == OP_NOP && opnum == 0 &&
  4439.               cap->count0 == 0 && cap->oap->regname == 0 && !p_im)
  4440.     vim_beep();
  4441.     clearop(cap->oap);
  4442.     if (p_im && !restart_edit)
  4443.     restart_edit = 'a';
  4444. }
  4445.  
  4446. #ifdef TEXT_OBJECTS
  4447. /*
  4448.  * "a" or "i" while an operator is pending or in Visual mode: object motion.
  4449.  */
  4450.     static void
  4451. do_object(cap)
  4452.     CMDARG    *cap;
  4453. {
  4454.     int        flag;
  4455.     int        include;
  4456.  
  4457.     if (cap->cmdchar == 'i')
  4458.     include = FALSE;    /* "ix" = inner object: exclude white space */
  4459.     else
  4460.     include = TRUE;        /* "ax" = an object: include white space */
  4461.  
  4462.     switch (cap->nchar)
  4463.     {
  4464.     case 'w': /* "aw" = a word */
  4465.             flag = current_word(cap->oap, cap->count1, include, FALSE);
  4466.             break;
  4467.     case 'W': /* "aW" = a WORD */
  4468.             flag = current_word(cap->oap, cap->count1, include, TRUE);
  4469.             break;
  4470.     case 'b': /* "ab" = a braces block */
  4471.             flag = current_block(cap->oap, cap->count1, include, '(');
  4472.             break;
  4473.     case 'B': /* "aB" = a Brackets block */
  4474.             flag = current_block(cap->oap, cap->count1, include, '{');
  4475.             break;
  4476.     case 'p': /* "ap" = a paragraph */
  4477.             flag = current_par(cap->oap, cap->count1, include, 'p');
  4478.             break;
  4479.     case 's': /* "as" = a sentence */
  4480.             flag = current_sent(cap->oap, cap->count1, include);
  4481.             break;
  4482. #if 0    /* TODO */
  4483.     case 'S': /* "aS" = a section */
  4484.     case 'f': /* "af" = a filename */
  4485.     case 'u': /* "au" = a URL */
  4486. #endif
  4487.     default:
  4488.             flag = FAIL;
  4489.             break;
  4490.     }
  4491.  
  4492.     if (flag == FAIL)
  4493.     clearopbeep(cap->oap);
  4494.     adjust_cursor_col();
  4495.     curwin->w_set_curswant = TRUE;
  4496. }
  4497. #endif
  4498.  
  4499. /*
  4500.  * Handle the "@r" command.
  4501.  */
  4502.     static void
  4503. do_at(cap)
  4504.     CMDARG    *cap;
  4505. {
  4506.     if (checkclearop(cap->oap))
  4507.     return;
  4508. #ifdef WANT_EVAL
  4509.     if (cap->nchar == '=')
  4510.     {
  4511.     if (get_expr_register() == NUL)
  4512.         return;
  4513.     }
  4514. #endif
  4515.     while (cap->count1--)
  4516.     {
  4517.     if (do_execreg(cap->nchar, FALSE, FALSE) == FAIL)
  4518.     {
  4519.         clearopbeep(cap->oap);
  4520.         break;
  4521.     }
  4522.     }
  4523. }
  4524.  
  4525. /*
  4526.  * Handle the CTRL-U and CTRL-D commands.
  4527.  */
  4528.     static void
  4529. do_halfpage(cap)
  4530.     CMDARG    *cap;
  4531. {
  4532.     if ((cap->cmdchar == Ctrl('U') && curwin->w_cursor.lnum == 1)
  4533.         || (cap->cmdchar == Ctrl('D')
  4534.         && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count))
  4535.     clearopbeep(cap->oap);
  4536.     else if (!checkclearop(cap->oap))
  4537.     halfpage(cap->cmdchar == Ctrl('D'), cap->count0);
  4538. }
  4539.  
  4540. /*
  4541.  * 'P' and 'p' commands.
  4542.  */
  4543.     static void
  4544. do_pput(cap)
  4545.     CMDARG  *cap;
  4546. {
  4547.     if (cap->oap->op_type != OP_NOP || VIsual_active)
  4548.     clearopbeep(cap->oap);
  4549.     else
  4550.     {
  4551.     prep_redo_cmd(cap);
  4552.     do_put(cap->oap->regname, cap->cmdchar == 'P' ? BACKWARD
  4553.                            : FORWARD, cap->count1, FALSE);
  4554.     }
  4555. }
  4556.